Sunday, August 30, 2009

AssemblyFileVersionAttribute and AssemblyVersionAttribute: A subtle difference

In Visual Studio 2008 (and possibly other versions) when you create a C# project in many cases the wizard also creates the AssemblyInfo.cs file for you. That's quite handy but it can also come with a surprise caused by a subtle difference. Usually both the AssemblyFileVersionAttribute and the AssemblyVersionAttribute are created for you. The generated code looks as follows:
// Version information for an assembly consists of the following four values:
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("")]
[assembly: AssemblyFileVersion("")]
The issue that you may run in is that when you read the comment and infer that it applies to both AssemblyVersion and AssemblyFileVersion. That is not the case! AssemblyVersion can deal with wild cards as the generated comment suggests. For AssemblyFileVersion "wild cards are not supported". There is a solution however. If you simply remove the AssemblyFileVersion, the version will be picked up from AssemblyVersion. as the Win 32 file version. And for AssemblyVersion you can use wild cards. In that case your code in AssemblyInfo.cs would look like this:
[assembly: AssemblyVersion("1.0.*")]
// No wild cards for AssemblyFileVersion!
//[assembly: AssemblyFileVersion("")]
// Since AssemblyFileVersion is commented out AssemblyVersion
// will be used for Win 32 file version.
So the recommendation is: Comment out AssemblyFileVersion unless you can't get away without it.

Thursday, August 20, 2009

ReSharper 4.5 Plugin for csUnit

Since I'm using csUnit and ReSharper in combination I certainly would like to have a better integration here. While JetBrains provides as part of their PowerToys the source code for a csUnit plugin, it unfortunately lacks a few things, e.g. the latest PowerToys set of files seems to be incomplete. For example the readme file refers to folders and files that are not included. Also, the sources for the csUnit plugin that are included in PowerToys create a number of compile errors when compiled against ReSharper 4.5. Apparently the examples weren't updated from previous versions, and R# 4.5 has a few breaking changes.
So I decided to update the example code and also add it to the csUnit source code. Here are two screen shots. The first one shows the editor with R#'s adornments on the left The second screenshot shows a window of R# displaying the result of a test run: The ReSharper plugin for csUnit is planned to be included in csUnit 2.7, which we plan to release in a few months. We haven't decided yet on the final date.

Sunday, August 16, 2009

Calling Process.Modules reliably

Namespace System.Diagnostics contains the class Process. With this class you can determine how many modules your process has loaded, even across multiple domains. There is a catch, however, since accessing the property Process.Modules may throw a Win32Exception. This property may be empty in which case Microsoft's documentation recommends to use WaitForInputIdle() to before retrieving the property. Before you access it you don't know, and if you do and it is empty at that point you'll get the Win32Exception. You can also call Process.WaitForInputIdle() just before you access Process.Modules, just to be on the safe side. However, using WaitForInputIdle() may throw an exception as well in certain circumstances. I couldn't find this exception mentioned in the documentation for WaitForInputIdle(), though. Therefore I decided to create a little helper method to make retrieving Process.Modules more reliable. Here is my code:
private static int GetModuleCount() {
  var currentProcess = Process.GetCurrentProcess();
  try {
     return currentProcess.Modules.Count;
  catch(Win32Exception) {
     // Wait until input message is empty and retry.
     return currentProcess.Modules.Count;
The first attempt assumes that the message loop is empty and the process in idle. If that call fails the code assumes that indeed more messages need to be processed so it waits until no further input needs to be processed. Then it simply tries again. If you need this method in several places in your code then you may also want to consider to create it as an extension method for class Process. I didn't implement the above code as an extension method since I needed it only in once place (hence it is a private method).

Friday, August 14, 2009

Some Tips for TeamCity

We are using TeamCity for continuous integration. Here I'll give provide a few tips in particular for people who are less familiar with Java. (After all this is a .NET blog!) Starting with the free Professional Edition we quickly decided to go for the Enterprise Edition to get unlimited build configurations and LDAP integration. Migrating from the built-in HSQL to a separate database server and integrating to LDAP wasn't overly complicated, although it certainly helps if you have access to JetBrain's support. So here are my tips for TeamCity:
  1. Use a separate database server from the beginning. That way you save the database migration.
  2. When you migrate the database you execute a piece of Java code. You may have to specify a parameters for the JVM. Since the first attempts failed I had to tell the tool to clean out the target database first. To do this in the file migrateDB.bat locate the line that starts with "SET MIGRATION_JVM_OPTS". Add "-DforceClean=true" to the options. This will drop all tables in the target database. (You don't want to do that once you have migrated, so best is to remove this immediately after a successful migration!)
  3. In some cases the migration will fail and the error messages may not necessarily be a big help unless you have done migrations plenty of times. In my case I had a path to the old server configuration wrong. So check that as well.
  4. If the migration fails then check the log files. They provide good information.
  5. When specifying paths anywhere use forward slash instead of backslash, even on Microsoft platforms.
Now our deployment is on a separate database and it actually improved the performance. Moving to LDAP avoids quite a bit of administrative work. All runs smoothly. Thanks to to Serge, Leonid, and Yegor of JetBrains for their fantastic support!

Sunday, August 09, 2009

Windows API Code Pack for .NET

Trying to stay on top of the latest UI developments of Windows was never easy not only from a technical perspective. At times it also appeared as if Microsoft tried to make sure that new controls made their way into Microsoft Office first just so their applications were the only ones with the most recent user experience. On the other hand things seem to change. Microsoft makes newer user experience elements available sooner. Maybe the reason is that drumming up support for a newer operating system like Windows 7 is faster. Be it as it is. On August 06, 2009, Microsoft published an updated version of the Windows API Code Pack that gives you quite a few new elements you can leverage for your applications. For example you can programmatically control the appearance of the taskbar for your application by providing jump lists and reporting back progress. Get the Windows API Code Pack for .NET here. There also a few links to videos that show how to use some of the features. While some of the items work for Windows 7 only, some of them will work on older Windows versions as well.