Web Site Performance and Assembly Versioning – Part 3 Versioning Combined Files Using Mercurial

Minification and Concatination of JavaScript and CSS Files
Versioning Combined Files Using Subversion
Versioning Combined Files Using Mercurial – this post

I have worked on a project recently where there was a need to version the system (library dll, css and javascript files) by date and Mercurial revision number. This was in the format:-


{major}.{year}.{month}{date}.{mercurial revision}

Each time there is an internal build using the CI server, it would label the files using this format. When it came time to do a major release, it became v1.{year}.{month}{date}.{mercurial revision}, with each public release having a major version increment.

Also as a requirement, each assembly also had to have a new GUID on each build.

So like in previous posts, we need to edit the csproj file, and add a couple of Default targets.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Project ToolsVersion="4.0" DefaultTargets="Hg-Revision;AssemblyInfo;Build" 
   3:     xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   4: <PropertyGroup>

Right below the closing tag of the entire project we add our two targets, the first is to get the Mercurial revision number. We first need to import the tasks for MSBuild which can be downloaded from http://msbuildhg.codeplex.com/

   1: <Import Project="..\Tools\MSBuild.Mercurial\MSBuild.Mercurial.Tasks" />
   1: <Target Name="Hg-Revision">
   2:  <HgVersion LocalPath="$(MSBuildProjectDirectory)" Timeout="5000" 
   3:     LibraryLocation="C:\TortoiseHg\">
   4:   <Output TaskParameter="Revision" PropertyName="Revision" />
   5:  </HgVersion>
   6:  <Message Text="Last revision from HG: $(Revision)" />
   7: </Target>
With the main Mercurial files being located at c:\TortoiseHg

To get a valid GUID we need to escape from the csproj markup and call some c# code which we put in a property group for later reference.

   1: <PropertyGroup>
   2:  <GuidGenFunction>
   3: <![CDATA[ 
   4: public static string ScriptMain() { 
   5: return System.Guid.NewGuid().ToString().ToUpper(); 
   6: } 
   7: ]]>
   8:  </GuidGenFunction>
   9: </PropertyGroup>

Now we add in our target for generating the GUID.

   1: <Target Name="AssemblyInfo">
   2:     <Script Language="C#" Code="$(GuidGenFunction)">
   3:       <Output TaskParameter="ReturnValue" PropertyName="NewGuid" />
   4:     </Script>
   5:     <Time Format="yy">
   6:       <Output TaskParameter="FormattedTime" PropertyName="year" />
   7:     </Time>
   8:     <Time Format="Mdd">
   9:       <Output TaskParameter="FormattedTime" PropertyName="daymonth" />
  10:     </Time>
  11:     <AssemblyInfo CodeLanguage="CS" OutputFile="Properties\AssemblyInfo.cs" 
  12:         AssemblyTitle="name" AssemblyDescription="description" 
  13:         AssemblyCompany="none" AssemblyProduct="product" 
  14:         AssemblyCopyright="Copyright ©" 
  15:         ComVisible="false" CLSCompliant="true" Guid="$(NewGuid)" 
  16:         AssemblyVersion="$(Major).$(year).$(daymonth).$(Revision)" 
  17:         AssemblyFileVersion="$(Major).$(year).$(daymonth).$(Revision)" />
  18:   </Target>

So this will give use an AssemblyInfo.cs file like this just prior to calling the Build task:-

   1: using System;
   2: using System.Reflection;
   3: using System.Runtime.CompilerServices;
   4: using System.Runtime.InteropServices;
   6: [assembly: AssemblyTitle("name")]
   7: [assembly: AssemblyDescription("description")]
   8: [assembly: AssemblyCompany("none")]
   9: [assembly: AssemblyProduct("product")]
  10: [assembly: AssemblyCopyright("Copyright ©")]
  11: [assembly: ComVisible(false)]
  12: [assembly: CLSCompliant(true)]
  13: [assembly: Guid("9C2C130E-40EF-4A20-B7AC-A23BA4B5F2B7")]
  14: [assembly: AssemblyVersion("0.12.524.407")]
  15: [assembly: AssemblyFileVersion("0.12.524.407")]

Therefore giving us the correct version for the assembly. This can be referenced within your project whether web or Windows based like this:-

   1: public static string AppVersion()
   2:  {
   3:    return Assembly.GetExecutingAssembly().GetName().Version.ToString();
   4:  }

As mentioned in previous posts in this series, you can label css and javascript files using this version number and the GetAssemblyIdentity task from the main MSBuild task library build into the .Net framework.

   1: <GetAssemblyIdentity AssemblyFiles="bin\TheAssemblyFile.dll">
   2:  <Output TaskParameter="Assemblies" ItemName="MyAssemblyIdentities" />
   3: </GetAssemblyIdentity>

Then use this to write out the files:-

   1: <WriteLinestoFile 
   2:     File="Client\site-style-%(MyAssemblyIdentities.Version).combined.min.css" 
   3:     Lines="@(CSSLinesSite)" Overwrite="true" />

No Comments