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:
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 18.104.22.168. You also have a project that references that assembly, called Bar.exe.
If you update the Foo.dll class library to AssemblyVersion 22.214.171.124, 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
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:
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 126.96.36.199 with the new-hotness Foo.dll version 188.8.131.52, 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.
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:
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:
It’s about as painless as it gets, and it even works with automatic versioning.