Thursday, November 30, 2006

NUnit and Visual Studio 2003

In any typical application that I'm asked to develop, there is an assembly of business objects I'm compelled to unit test. So I create a new project to the solution with ".Test" appended to the name (e.g to unit test the CDMA.Business assembly, I'd create a new CDMA.Business.Test class library project that references both the CDMA.Business and nunit.framework assemblies). Frequently, the subject of unit tests depends on application configuration settings, so I'll create a new file called CDMA.Business.Test.dll.config (note that this is the name of the assembly, with ".config" appended) within the test project and then I'll add a new Post-build event to copy the file to the target directory. Project Properties -> Common Properties -> Build Events -> Post-build Event Command Line:

xcopy /y "$(ProjectDir)$(TargetFileName).config" "$(TargetDir)"

To enable debugging via the F5 key, I'll use the following settings in Project Properties -> Configuration Properties -> Debugging:

Debug Mode: Program
Start Application: C:\Program Files\NUnit 2.2.8\bin\nunit-gui.exe
Command Line Arguments: CDMA.Business.Test.dll

If you then set your unit test project as the start up project you can just press the F5 key and Visual Studio will automagically build the project, copy the configuration file, run the nunit-gui executable and attach the debugger to it. To skip the last step, just press CTRL-F5 instead.

Sunday, November 19, 2006

C# 3.0

Ted Neward explains how the new features are nothing more than syntactic sugar that makes programmers' lives a little easier. For example, all the IL code produced by the C# 3.0 compiler can be reverse engineered by Lutz Roeder's .NET Reflector to show you how the feature's actually been implemented. Brilliant.

Wednesday, November 15, 2006

Extension Methods to the Rescue

Today I added some caching to a prototype application I'm developing at work. Microsoft Enterprise Library was my implementation library of choice, but I was frustrated by the choice of available overloads for CacheManager.Add(). Rather than add my own overload, spoil the clean interface and recompile the assembly, I ended up writing a single method on a static class that took an instance of the CacheManager, key, value and expiration as parameters, adding in the default values in a call to the CacheManager object. Now this may not be object-oriented, but it's very similar to how extension methods work in C# 3.0 (in my opinion, they exist solely to _fake_ the object-orientedness in calling code). In fact, when you declare a class like this:

public static class CacheManagerExtension
public static readonly TimeSpan DefaultAbsoluteExpiration = TimeSpan.FromMinutes(5);
public static void Add(this CacheManager cacheManager, string key, object value, TimeSpan absoluteExpiration)
cacheManager.Add(key, value, ..., new AbsoluteExpiration(absoluteExpiration), ...);

the new C# 3.0 compiler (figuratively speaking) recognises the "this" keyword in the parameter list, and marks the method, class and assembly with the ExtensionAttribute custom attribute. Now, you can call the Add method like this:

cacheManager.Add(key, value, CacheManagerExtension.DefaultAbsoluteExpiration);

and the compiler (and hopefully Intellisense) - upon realising that no method with that signature exists on the CacheManager class - will translate it into a call on the static class marked with the ExtensionAttribute attribute.

Oh yeah, and my other gripe with Microsoft Enterprise Library is the fact it's caching is not aspect-oriented, but that's the topic of another post...

Post-script: Don't blindly assume that your service delivery team are happy to install EntLib on the production server. :-)

Using log4net

log4net is my recommended lightweight tool for emitting log statements from .NET code. I'm a firm believer that application users shouldn't see exception messages or stack traces - that information is for system administrators and developers only. I like storing log information in a database or in a text file on the server and allowing developers to view it when things start to go pear shaped.

Here's how I typically set up log4net on a project:

- Create a sub directory within your solution - called 3rdParty - and copy the log4net assembly there. This allows meto store one copy of the assembly, and reference it from all projects in the solution.
- Create a separate configuration file that I call log4net.config (I don't use Web.config or App.config)
- Use the XmlConfigurator custom attribute on the assembly that will be loaded first
(Don't forget to set the Watch property to true)
- Start appreciating the benefits of logging!

NOTE 1: If you do choose to use Web.config or App.config, the only reason you have to declare the IgnoreSectionHandler is for .NET to ignore the log4net section!

NOTE 2: No, I don't know what line of code causes the XmlConfiguratorAttribute to be reflected and subsequently configured.

Tuesday, November 14, 2006

C# 3.0 is not dotnetfx3; repeat;

I am a little behind the times, it seems, as Microsoft released .NET Framework 3.0 just a few days ago. Luckily, the release is true to it's name - it's just another version of the framework with the recent additions WCF, WWF, WPF and CardSpace(collectively and formerly known as WinFX). It contains neither C# 3.0 nor LINQ, both of which will be released with "Orcas". Phew. That means I have time to brush up on my knowledge of automatic type inference before a random client starts asking tough questions!

Sunday, November 12, 2006

Technical Forum

If I could offer you only one tip for the future, ______ would be it. I've tentatively accepted a spot to speak on a technical subject at a forum of consultants, but I haven't yet chosen the topic. It's my first foray into the world of presentations; I don't expect it to go swimmingly but if I can judge the level of my audience and give them something useful then my job will have been done. Actually, I will judge it a success if the audience can go away and apply some practise they learned from me (or were inspired to learn by the topic).

To meet this goal, the focus needs to be on both the content and its delivery. I hope I can do it!

Exception Handling

OMF! My blood reached boiling point this week when I overheard a colleague whining when his poorly structured error handling and logging mish-mash was removed from the codebase. Similarly, it boiled a couple of months ago when a group of fellow consultants were encouraging a user interface element that would generically display stack trace information to users. Please, people, follow these guidelines:
a) Stack trace (or even exception type information) should NEVER be shown to users because you don't know what kind of sensitive (perhaps proprietary) information is contained within.
b) DON'T append long dynamic SQL statements (or any other information used solely for diagnostic purposes) to your Exception's Message property so that it can be displayed on the screen, unencrypted, rather log it separately.
c) DO use a framework like Microsoft's Enterprise Library, or a component like log4net to trace information rather than displaying it in the end user's UI.