Archive for category Microsoft .NET
I have always found it useful for applications to display their build version, and for libraries to have the build version in their properties. Relying on properties like the date (or file size) is always a bit risky.
.NET Core has embraced Semantic Versioning and at first glance appears to have a new way to specify version numbers.
It doesn’t quite work to my full satisfaction, but luckily the older methods still work, so a basic GitVersion task in your build pipeline is pretty much all you need to get things working.
Following hot on the heels of v2 of Essential.Diagnostics, work on the beta version of the Essential.Diagnostics.SeqTraceListener has been completed, and it has been published to NuGet.
PM> Install-Package Essential.Diagnostics.SeqTraceListener
This provides a trace listener implementation that forwards messages to a Seq logging server. For performance it forwards messages in batches (with the first message being sent immediately, so you know the system is up and running), with automatic back off and retry when there are interruptions to the network communication.
This component can be used with the new Microsoft.Extensions.Logging for .NET 4.5.1 and above, or with Sytem.Diagnostics.TraceSource for .NET 2.0 through 4.5.
I have made significant changes in the organisation of the Essential.Diagnostics project; although none of the actual implementations have changed, the project has been split into separate packages for each trace listener, available via NuGet.
The project also has a new logo:
Following on from my colleague Mitch Denny’s Federated Identity in Visual Studio Online, I have expanded his work on the directory architecture and partner integration for Visual Studio Online, and expanded to include the other architectural components of a VSO environment such as build servers, deployment targets, and cloud-based load testing.
I added a comparison of the major logging/tracing frameworks for .NET to the CodePlex site for Essential.Diagnostics, to demonstrate how System.Diagnostics stacks up against log4net, NLog and the Enterprise Library.
I also added a performance comparison (the source code is in the CodePlex project if you want to verify the results).
Look at the results for yourself, but I think System.Diagnostics does okay — and the extensions in Essential.Diagnostics (plus others such as Ukadc.Diagnostics and UdpPocketTrace) fill out the gaps compared to log4net and NLog. Similarly on the performance side, all have very little overhead (NLog is a winner on overhead, but does relatively worse on actually writing the messages to a log file).
What about the Enterprise Library Logging Application Block? Well, I just don’t think it does well compared to the others. Sure it was a lot better than .NET 1.0 System.Diagnostics, but a lot of that was added in .NET 2.0 System.Diagnostics (such as multiple sources). In some cases it is worse than what is currently available in the standard framework — e.g. no delayed formatting. This shows up in the performance figures which indicate several magnitudes greater overhead than any of the other frameworks!
I’m obviously biased, but I really think that the best solution is to stick with the standard, out-of-the-box, System.Diagnostics, extended where necessary to fill any gaps (Essential.Diagnostics, etc, for additional listeners, filters & formatting).
P.S. Also check out my guidance on Logging Levels.
Essential.Diagnostics is a library of additional trace listeners and other bits for the .NET Framework System.Diagnostics trace logging.
It doesn’t change the way you write log statements (you still use TraceSource), but fits into the built-in extension points to add functionality (mostly additional trace listeners and filters).
From the project description:
“Essential.Diagnostics contains additional trace listeners, filters and utility classes for the .NET Framework System.Diagnostics trace logging. Included are colored console (that allows custom formats), SQL database (including a tool to create tables) and in-memory trace listeners, simple property and expression filters, activity and logical operation scopes, and configuration file monitoring.”
The intention is to round-out System.Diagnostics with additional capabilities so that it can be compared to alternative 3rd party logging systems (NLog, log4net, Common.Logging, and even Enterprise Library).
Note that the library is intentionally much lighter than Enterprise Library; rather than an overhaul of the logging mechanism itself the library is mainly meant to provide additional trace listeners.
I put the source code up a few days ago, but only recently finished the packaging scripts for the downloads.
With the recent release of
NuPack NuGet, I have also spent an additional bit of time and set it up as a NuGet package.
A colleague, Richard Banks, has previously blogged on this topic (http://www.richard-banks.org/2010/07/how-to-versioning-builds-with-tfs-2010.html), using custom activities and modifying the build workflow.
However, I also like the approach taken by John Robbins (http://www.wintellect.com/CS/blogs/jrobbins/archive/2010/06/15/9994.aspx).
John’s approach is done entirely within the build file, using some of the new features of MSBuild 4.0, and therefore has no dependencies except what is already on a TFS build server.
Based heavily on John’s work, I’ve created my own build targets that are based on the same core features but tailored to the way I like to work.
The build number is still based on the TFS build number, however rather than a base year of 2001 I pass it in as a property. This avoids the problem that a build on 31 Dec 2012 could be number 1.0.51231.1, whereas the one on 1 Jan 2013 would be 220.127.116.11. By setting the base year to the year your project starts you ensure your build numbers start low and increase.
(If you start reaching the end, after five years or so, you can always reset the base year after changing the minor version).
I also have an option to read the major and minor versions from the existing AssemblyInfo.cs file, rather than having them set in the build script, which I find a useful way to allow me to change the version number.
Like John’s script, I only update AssemblyFileVersion, which can help in a multiple-project situation where there are version dependencies on strong names (such as in config files).
However, rather than a central shared version info file, I write the updated version number back into the projects AssemblyInfo.cs file.
The benefit of John’s original approach is that you can have a separate project dependency that updates a central file for all builds, whereas with my approach you need to update each project’s build (.csproj) file. On the other hand the negative with the original approach is that you need to change the structure of projects to point to the shared file, whereas I keep them self-contained with the original AssemblyInfo.cs file (similar to Richard’s approach).
I only made changes to the C# project type, which is where I do most of my work, and so don’t support all the project types that John’s script does (VB.NET, C++, etc).
The only other output I have implemented is writing straight into a text file, which I find useful to copy to the output directory as a easy way to reference the build. This is particularly useful for web projects, where they are a directory full of .aspx files (and you can also hit the Version.txt file from a browser).
To use the script, include the TFSBuildNumber.targets file somewhere in your solution or project, then copy the example lines from Example.csproj to the .csproj files for projects you want to version.
To do this from within Visual Studio, first you need to right click and unload the project, then right click and open the file for editing. After pasting in the code, save and close the file, then reload the project.
The end of your .csproj file should look something like this (alter the path depending on where you placed the TFSBuildNumber.targets file):
... <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. --> <PropertyGroup> <TFSBaseBuildYear>2010</TFSBaseBuildYear> </PropertyGroup> <Import Project="..\TFSBuildNumber.targets" /> <Target Name="BeforeBuild" DependsOnTargets="GetMajorMinorFromCSharpAssemblyInfoFile;WriteProjectTextAssemblyVersionFile;UpdateCSharpAssemblyInfoFile"> </Target> </Project>
One benefit of having the version numbers line up with the TFS build numbers is that given a particular DLL you can check the version number and then easily translate to the particular build it came from, e.g. (with a base year of 2010) the version number 1.0.924.5 comes from TFS build number 20100924.5.