C# assembly automatic versioning

I’m trying to get my build pipeline a little more automated, scripted, hands-off, etc.

In this endeavor, I decided to go back to automatic version numbering, which is a feature of the C# compiler.

A quick review. There are two possible version numbers that you can put into your AssemblyInfo.cs file:

[assembly: AssemblyVersion("1.0.0.0")]

and

[assembly: AssemblyFileVersion("1.0.0.0")]

AssemblyVersion

The first version number, AssemblyVersion, is really important. It is used by the .NET loader (aka Fusion), to determine which version of classes are in the assembly. It’s read at runtime, and is stored as .NET-readable metadata within the assembly. Many references are done using strong names, which includes the version number as part of the name. It’s this attribute that sets the version number that counts in the strong name.

For example, let’s say you have a class library Foo.dll that has AssemblyVersion 1.2.3.4. You also have a project that references that assembly, called Bar.exe.

If you update the Foo.dll class library to AssemblyVersion 1.2.3.5, then Bar.exe will not be able to load it unless it has a BindingRedirect configuration.

For this reason, I prefer to manually update the AssemblyVersion using Semantic Versioning rules. Because Semantic Versioning uses a triple, and not a quad

AssemblyFileVersion

The second version number, AssemblyFileVersion, is ignored by the .NET loader, but it can be helpful for people and deployment automation. It is stored in the Portable Executable (PE) header, and can be seen in the Properties dialog shown by Windows Explorer, as well as PowerShell, using this script:

Get-ChildItem .\Foo.dll | Select-Object -ExpandProperty VersionInfo | Select-Object FileVersion | Select-Object -ExpandProperty FileVersion

or, the same script, but using standard PS aliases and properties:

(gci .\Foo.dll).VersionInfo.FileVersion

Using the example above, if you need to make a minor patch to Foo.dll, then you might want to leave the AssemblyVersion value alone, so that you don’t need to create a BindingRedirect for every client that needs to use the new assembly. To ensure that you are actually replacing the old-and-busted Foo.dll version 1.2.3.4 with the new-hotness Foo.dll version 1.2.3.5, you would change the value of AssemblyFileVersion, not AssemblyVersion.

This attribute is optional. If you don’t supply it, then .NET will use AssemblyVersion for the PE version information.

Automatic versioning

The C# compiler is capable of generating new version numbers automatically. Specifically, it can generate any of the final two parts of the four-part version number.

For example, these are valid AssemblyVersion values:

[assembly: AssemblyVersion("1.0.0.*")]

or

[assembly: AssemblyVersion("1.0.*")] 

I’ll tell you right now: do not use N.0.0.*. This is because the way these numbers are generated is based on a day count for the third part (the build number), and a time-of-day for the fourth part (the revision number). See AssemblyVersionAttribute docs for the details. If you build the assembly over several days, the revision number will not always increment. This is bad.

You should only ever use N.0.* if you want automatic versioning.

Working with Nuget packaging

I recently discovered how easy it is to package DLLs for re-use using Nuget. It’s especially easy if you have a Visual Studio project.

And I just discovered this even easier way:

http://blog.danskingdom.com/automatically-create-your-projects-nuget-package-every-time-it-builds-via-nuget/

Also see https://github.com/deadlydog/New-NuGetPackage

It’s about as painless as it gets, and it even works with automatic versioning.

Author

Alan McBee

comments powered by Disqus