April 2010 - Posts
I wanted to configure version information generation for some .NET projects. It’s been a long time since I investigated available options, so I searched around hoping to find some simple way of doing this. What I’ve found didn’t look very encouraging: people write Visual Studio add-ins and custom MsBuild tasks just to obtain one integer number (okay, maybe two). This felt overkill for a small personal project.
The inspiration came from one of the StackOverflow discussions where somebody suggested that T4 templates could do the job. And of course they can. The solution requires a minimal effort and no Visual Studio or build process customization. Here what should be done:
1. Create a file with extension ".tt" and place there T4 template that will generate AssemblyVersion and AssemblyFileVersion attributes:
<#@ template language="C#" #>
//
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
//
using System.Reflection;
[assembly: AssemblyVersion("1.0.1.<#= this.RevisionNumber #>")]
[assembly: AssemblyFileVersion("1.0.1.<#= this.RevisionNumber #>")]
<#+
int RevisionNumber = (int)(DateTime.UtcNow - new DateTime(2010,1,1)).TotalDays;
#>
You will have to decide about version number generation algoritm. For me it was sufficient to auto-generate a revision number that is set to the number of days since January 1st, 2010. As you can see, the version generation rule is written in plain C#, so you can easily adjust it to your needs.
2. The file above should be placed in one of the projects. I created a new project with just this single file to make version management technique clear. When I build this project (actually I don’t even need to build it: saving the file is enough to trigger a Visual Studio action), the following C# is generated:
//
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
//
using System.Reflection;
[assembly: AssemblyVersion("1.0.1.113")]
[assembly: AssemblyFileVersion("1.0.1.113")]
Yes, today it’s 113 days since January 1st, 2010. Tomorrow the revision number will change.
3. Next step is to remove AssemblyVersion and AssemblyFileVersion attributes from AssemblyInfo.cs files in all projects that should share the same auto-generated version information. Instead choose “Add existing item” for each projects, navigate to the folder with T4 template file, select corresponding “.cs” file and add it as a link. That will do!
What I like about this approach is that it is lightweight (no custom MsBuild tasks), and auto-generated version information is not added to source control. And of course using C# for version generation algorithm opens for algorithms of any complexity.
I am currently working on a next version of a utility to generate Visual Studio solutions. A new version will be called Solution Maker and add user interface support to a command line option. I wanted to mix console and GUI mode in a single program, but strictly speaking this is impossible. A program is assigned its type at compile time, so any attempt to change it’s behavior at execution time does not alter the application’s nature. A console application may create Windows forms, and a Window-based application may allocate consoles, but they won’t become ducks even if they quack.
But Visual Studio does it, don’t it? You can launch IDE and still you can run “devenv” from a command-line. How does it do it?
Well, actually it doesn’t! Here’s an explanation of the trick. There two binaries: devenv.com and devenv.exe. “Com” is always probed first, and this is the console one. So when you type “devenv” it’s a console version that will be executed. And if it does not get any command-line input, it simply launches devenv.exe. Smart!
And this can be done with any application. Here are the steps:
- Write an application with user interface, let’s say it’s called MyProgram.exe. This program should not have anything special.
- Write a command line application MyProgram.Command.exe. This program needs a few special lines, we will look at them.
- Rename MyProgram.Command.exe to MyProgram.com and copy it to the folder where GUI MyProgram.exe resides.
That’s it. And of course, command-line version of MyProgram needs some special code. Here it is:
class Program
{
static void Main(string[] args)
{
string relayProcessPath = null;
// Only relay to another application if no command-line arguments are specified
if (args.Length == 0)
{
string thisProcessPath = Process.GetCurrentProcess().MainModule.FileName;
if (Path.GetExtension(thisProcessPath).ToLower() == ".com")
{
// Relay process should only differ in extension
string expectedRelayPath = Path.ChangeExtension(thisProcessPath, ".exe");
if (File.Exists(expectedRelayPath))
{
relayProcessPath = expectedRelayPath;
}
}
}
if (!string.IsNullOrEmpty(relayProcessPath))
{
// Launch relay process
Process.Start(relayProcessPath);
}
else
{
// Process with a command line
Console.WriteLine("Hello from command line");
}
}
}
It’s difficult to resist giving a try to Git or Mercurial these days, and I decided to start moving the code of my personal projects to DVCS. I’ve chosen Bitbucket as a remote storage for my repositories. It seems to have very good reputation, and it’s subscription plans include a free plan for a single private repository (up to 1 GB) with upgrades starting as low as $5 a month.
I am just making my first steps with Mercurial, so I read Joel Spolsky’s Hg Init introduction, but Bitbucket also contains guidelines that make setting up repository a simple excercise.
It’s easy enough to manage source control using Hg commands, but TortoiseHg installs a Windows shell extension that turns Windows Explorer into a source control management tool.
And finally, for those spoilt by Visual Studio source control integration, VisualHG is a Mercurial plug-in for Visual Studio.
I installed all of the above packages and was surprised how quickly I was up and running my source against remote Mercurial repository at Bitbucket. And I definitely enjoy the experience. Comparing to TFS I like the mobile nature of my local sources. Like every centralized version control system, TFS prefers its users to be connected. You can bring your projects offline, but this is considered to be a temporary state. As soon as you can connect to TFS, you are supposed to do it so it can synchronize your changes. Distributed version control systems have different phylosophy, there are no connected and disconnected users, and you can work and commit your changes locally and only push them to a remote repository for planned release or synchronization.
One thing for sure: no more source control at home. In 1993 I bought a Microsoft Delta license for my personal use. Later I upgraded it to SourceSafe (at that time not yet “Visual”). All this time I had source code repository on one of my home machines. No more. “hg push” command will make Bitbucket take care of my source.
I hope that volcano (how is it called by the way? Ey… Eja… Ejafaja… oh no! it’s Eyjafjallajokull – can anyone actually manage it without Google?) won’t disturb air traffic in Norway in the end of April. Because on 27th and 28th Typemock is arranging Typemock Academy. With special appearance of one-and-only Uncle Bob. And who do you think will be one of the guest speakers? Well, I am modest, I won’t tell you.
Anyway, I got 60 minutes to share my testing experience. “A Road to True Unit Test”. This is a preliminary title of my presentation. Working on details…
For a long time I’ve been under impression that rule engine that comes with Microsoft Windows Workflow Foundation is slow, very slow. We used it to execute some of our business rules, and soon found out that rule processing slows down application execution. What was strange is that the rules were really simple and it was hard to believe that an industry-strength rule engine uses so long time on processing them.
Eventually I ran a profiler, and it immediately showed where the time was spent. In fact it was not the actual rule validation but preparation for it: instantiation of the WF rule parser. The parser class is not public, so we used a trick to obtain its instance: retrieved its non-public constructor information via reflection and then called Invoke.
This was sloooow. So slow that we noticed it in our integration tests. What made it noticeable is that after we converted some of our business rules to use WF rule engine, we were encouraged by results and move more rules to use the same techinque. In the end rule validation was called many times during a single business operation, and performance deteriorated.
My first approach to this issue was to cache validated rules, and it worked. The total time to execute integration tests was reduced by 50%. However, I was not quite happy with the situation: we have various places where objects are instantiated using reflection, caching is not always possible and in general complicates component design. Recently I reviewed the code of StructureMap (I like reading good code), and remembered that it no longer used reflection and instead instantiated dependencies using compiled lambda expressions.
Roger Alsing in this post presented a generic method that can be used as a replacement for constructor method invocation. The essence of the method is in it’s last three lines:
// Make a NewExpression that calls the ctor with the args we just created
NewExpression newExp = Expression.New(ctor, argsExp);
// Create a lambda with the New expression as body and our param object[] as arg
LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param);
// Compile it
ObjectActivator compiled = (ObjectActivator)lambda.Compile();
Although lambda expressions are part of LINQ (and you have to import System.Linq.Expressions namespace to manage them), as we can see from this example, they can be very useful to solve core language tasks, such as object instantiation.
But what is the gain? The gain is huge bringing the performance close to the speed of native IL code. I wrote a few tests to measure performance of object creation in different scenarios: by calling ‘new’ constructor, Activator.CreateInstance, ConstructorInfo.Invoke and using compiled lambda expression. Here are the results:
DefaultConstructor_Activator: (0,20 ms per 1000 calls)
DefaultConstructor_CompiledExpression: (0,04 ms per 1000 calls)
DefaultConstructor_Invoke: (1,07 ms per 1000 calls)
DefaultConstructor_New: (0,02 ms per 1000 calls)
DefaultConstructor_NotCompiledExpression: (169,00 ms per 1000 calls)
NonDefaultConstructor_Activator: (3,39 ms per 1000 calls)
NonDefaultConstructor_CompiledExpression: (0,07 ms per 1000 calls)
NonDefaultConstructor_Invoke: (1,57 ms per 1000 calls)
NonDefaultConstructor_New: (0,02 ms per 1000 calls)
NonDefaultConstructor_NotCompiledExpression: (293,00 ms per 1000 calls)
Results says it all, especially when arranged in a graph.
I removed from the graph the results for not compiled lambda expressions, because they make other figures insignificant. But it is important to remember that compilation should be performed only once, so the code should be carefully reviewed to avoid occasional recompilcation of lambdas.
P.S. The title of this blog post may look provocative, and of course I don’t really mean somebody should completely stop using Activator.CreateInstance. Compilation of labmda expressions is expensive enough to limit it’s practical use. But there are certain use cases (like IoC frameworks) when it gives clear performance advantage.