westtech.dev something to know

Sitecore Custom Login Details With Version

Originally published on michaellwest.blogspot.com

It sure has been a while since I last posted anything interesting…or anything at all! I recently spoke with +Michael Reynolds about blogging but rather than blog I decided to read all the tweets about the Sitecore Symposium :(

Now it’s time to pick it back up. What you will see in here isn’t all that new, but it is however very useful. Also, at the bottom I have listed a few blogs I know of that cover the same topic. Two of which are far more interesting than mine so be sure to have a look.

Recently at work an issue came up where the QA team did not know if the test environment had the correct build applied (TDS package). I decided to use some old code from a version page I created for the same issue with an Asp.net applications.

The following is a list of files that we will create to make the magic happen.

  • ReflectionUtil.cs : Generic reflection code to extract version details from the loaded assembly.
  • ApplicationDetails.cs : Pipeline to extract version information.
  • Sitecore.SharedSource.Version.config : Pipeline configuration
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

using System.Text;
using Sitecore.SharedSource.Reflection;
using Sitecore.Pipelines.GetAboutInformation;

namespace Sitecore.SharedSource.Pipelines
{
    public class ApplicationDetails
    {
        public void Process(GetAboutInformationArgs args)
        {
            var text = new StringBuilder();
            text.Append("<span>Build</span></br><span>");
            text.Append(ReflectionUtil.GetExecutingAssemblyDetail(ReflectionUtil.AssemblyDetailType.Date));
            text.Append("</span></br><span>");
            text.Append(ReflectionUtil.GetExecutingAssemblyDetail(ReflectionUtil.AssemblyDetailType.Version));
            text.Append("</span>");
            args.LoginPageText = text.ToString();
        }
    }
}
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

using System;
using System.IO;
using System.Reflection;

namespace Sitecore.SharedSource.Reflection
{
    public sealed class ReflectionUtil
    {
        /// <summary>
        /// Represents the type of detail to retrive from the assembly. The data is formatted and therefore will
        /// not appear exactly is seen through Microsoft Windows Explorer.
        /// </summary>
        public enum AssemblyDetailType
        {
            /// <summary>
            /// Indicates that no detail type is indicated.
            /// </summary>
            NotSpecified = 0,

            /// <summary>
            /// Indicates that the detail type is the name of the assembly.
            /// </summary>
            Name = 1,

            /// <summary>
            /// Indicates that the detail type is the version of the assembly.
            /// </summary>
            Version = 2,

            /// <summary>
            /// Indicates that the detail type is the date the assembly was compiled.
            /// </summary>
            Date = 3
        }

        #region Assembly

        /// <summary>
        /// Returns the details of the executing assembly specified by the <see cref="AssemblyDetailType"/>.
        /// </summary>
        public static string GetExecutingAssemblyDetail(AssemblyDetailType detail)
        {
            return AssemblyDetailHelper(detail, Assembly.GetExecutingAssembly());
        }

        /// <summary>
        /// Returns the details of the calling assembly specified by the <see cref="AssemblyDetailType"/>.
        /// </summary>
        /// <param name="detail">The type of information to extract from the assembly.</param>
        /// <returns></returns>
        public static string GetAssemblyDetail(AssemblyDetailType detail)
        {
            return AssemblyDetailHelper(detail, Assembly.GetCallingAssembly());
        }

        #region Helper

        private static string AssemblyDetailHelper(AssemblyDetailType detail, Assembly assembly)
        {
            switch (detail)
            {
                case AssemblyDetailType.Date:
                    return GetAssemblyDate(assembly);

                case AssemblyDetailType.Name:
                    return GetAssemblyName(assembly);

                case AssemblyDetailType.Version:
                    return GetAssemblyVersion(assembly);

                case AssemblyDetailType.NotSpecified:
                default:
                    return "No method implemented to return the requested details.";
            }
        }

        private static string GetAssemblyName(Assembly assembly)
        {
            var filepath = assembly.Location;
            var info = new FileInfo(filepath);
            var name = String.Format("Assembly: {0}", info.Name);
            return name;
        }

        private static string GetAssemblyVersion(Assembly assembly)
        {
            var version = assembly.GetName().Version;
            var versionMessage = String.Format("Version: {0}.{1}.{2}.{3}",
                                               version.Major, version.Minor, version.Build, version.MinorRevision);
            return versionMessage;
        }

        private static string GetAssemblyDate(Assembly assembly)
        {
            var date = RetrieveLinkerTimestamp(assembly);
            var dateMessage = String.Format("Date: {0}", date.ToString());
            return dateMessage;
        }

        private static DateTime RetrieveLinkerTimestamp(Assembly assembly)
        {
            var filePath = assembly.Location;
            const int cPeHeaderOffset = 60;
            const int cLinkerTimestampOffset = 8;
            var b = new byte[2048];
            Stream s = null;

            try
            {
                s = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                s.Read(b, 0, 2048);
            }
            finally
            {
                if (s != null)
                {
                    s.Close();
                }
            }

            var i = BitConverter.ToInt32(b, cPeHeaderOffset);
            var secondsSince1970 = BitConverter.ToInt32(b, i + cLinkerTimestampOffset);
            var dt = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(secondsSince1970);
            dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours);
            return dt;
        }

        #endregion Helper

        #endregion Assembly
    }
}
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <getAboutInformation>
        <!-- Pipeline to render application version details on the login page. -->
        <processor type="Sitecore.SharedSource.Pipelines.ApplicationDetails, Sitecore.SharedSource.Version" />
      </getAboutInformation>
      <initialize>
    </pipelines>
  </sitecore>
</configuration>

View on GitHub Gist

The final results are clean and simple.

The following is a list of other posts I found helpful.