Saturday, November 14, 2009

C# 4.0: MethodBag, ExpandoObject and other cool stuff

With the new features that are part of the DLR you can create plenty of cool stuff like Dynamic Method Bags, ExpandoObject, etc. More blogs, tutorials and articles will follow. And without doubt these new features have their place and will provide excellent value in those cases. However, always keep this in mind: "To a kid who gets a hammer for Christmas, everything looks like a nail." In economically challenging times you can prove your value even more by choosing carefully where, when and how you use new technology. Rumors has it that occasionally not using the newest features is the better choice ...

Monday, November 09, 2009

IE8 and Selenium RC: Tests won't execute

Just noticed that running tests through Selenium RC in Internet Explorer 8 (IE8) displays a message containing an info to disable pop-up blocker. IE reports a script error and also says that it cannot load "...htmlutils.js". The solution was simple: Run the Selenium RC server in admin mode. Launch the command line as administrator then start selenium RC using "java -jar selenium-server.jar". The scripts should then run. (Of course you would put all of this into a short script or batch file, which in turn is set to run "As Administrator". I observed this behavior on Windows Vista Ultimate 32 bit with IE8 and all of that updated to the latest patch level. The Selenium version was 1.0.1. The behavior might also be present in other combinations. Also the solution described above may or may not help on other tech stacks.

Sunday, November 08, 2009

ASP.NET Forms Based Authentication: Minimum Configuration

Where possible I try to implement functionality with the minimum code I can get away with. Yes, that means that I leave out all 'flexibilities' that are not needed right away even those that others would see as we will need them anyway tomorrow. Sometimes tomorrow never comes. Anyways. ASP.NET offers several options for authentication. For one application I chose forms based authentication. The minimum working configuration that I found looks as follows:
<authentication mode="Forms">
  <deny users="?"/>
Place this in your web.config file inside the system.web element. Of course it is likely that for production scenarios you will use something more sophisticated. However, for development purposes sometimes all you want is the minimum to get you started. And that's all the above is about.

Monday, November 02, 2009

ASP.NET, Master Pages and Selenium RC

Testing master pages in ASP.NET using Selenium can be tricky at the beginning since ASP.NET mangles the identifiers of controls on your pages. For example: You might have a form with an input text box. You give that text box the id 'myTextBox'. Then your Selenium RC test might look as follows:
public void MyTextBox() {
   _selenium.Type("myTextBox", "some content");
   // ... rest of the test
The problem with this is that the test will fail even if you have given your textbox the correct id. The reason for that is that ASP.NET mangles the identifier to something like "ctl00_..._myTextBox". You can't be sure how it is mangled next time when you compile the page or next time ASP.NET is update. The better approach is one that works regardless how the id is mangled so long as the original id is still included. So here we go:
public void MyTextBox() {
   _selenium.Type("//input[contains(@name, 'myTextBox')]", "some content");
   // ... rest of the test
Now of course you may need to locate an element more often so it makes sense to write a little method for this. With that method the test then becomes:
using csUnit;
using Selenium;

namespace MyWebSite.Web.Tests {
   public class WebSiteTests {
      private string XPathForInput(string identifier) {
         return string.Format("//input[contains(@name, '{0}')]", identifier);

      public void MyTextBox() {
         _selenium.Type(XPathForInput("myTextBox"), "some content");
         // ... rest of the test

      // ... rest of the fixture

      private ISelenium _selenium;
Although I found a few examples on the internet I thought that provide some concrete code might help you to get up to speed faster.

Sunday, November 01, 2009

WiX vs InstallShield

Until recently we used InstallShield for all our software packaging needs. It was never a love relationship as the product is complicated to use and we don't need the vast majority of its features anyways despite the fact we are deploying large enterprise systems consisting of multiple installers. Not long ago we ran into problems with InstallShield and tried to get to support. Understandably support is not available for free, so I sent an email to their sales department ("sales@...") "threatening" to even spend money on purchasing a support contract. I never received a reply. Since the issues we observed with the product didn't disappear and the information available on the internet, e.g. forums, didn't help either we look for alternatives. The packaging had been a long standing concern. So we looked again at WiX (Windows Installer Toolkit). It took one of my engineers not more than one month to rewrite all installers using WiX, and our next monthly release in November will be shipped entirely on WiX. Is WiX perfect? No, not at all. But we now have a tool that is much simpler to use and it fits very nicely with our other Visual Studio based tools. In addition: WiX is open-source and we don't have a licensing issue which is kind of nice as now not only all team members can use it at the same time but we can also always run our automated processes without even thinking about licensing issues. So overall I'm glad we took a fresh look at WiX and that we phased out InstallShield. Given the available service levels, the associated cost, and in particular the fact I never heard back from their sales department although I was willing to spend money, WiX is the better choice for us overall. And maybe it's also the better choice for your project?

Saturday, October 31, 2009

Web user interface testing? Selenium!

Working on a web based user interface? New or existing? Need automated testing? No problem: Use Selenium. Yes, it's Java-based but that's no reason for not using it. It also works for web development based on .NET. Selenium is nothing new for most .NET base developers. Still it might be worthwhile to have a brief look at how to integrate it with your solution. So here are the basic steps to make it work. First, of course, you need to download Selenium from here. The version that you most likely want to use is Selenium RC. Once downloaded, installation is very simple:
  1. Create a folder for Selenium. I typically use c:\bin\selenium (I hate typing double quotes and stuff for command lines if folder names contain spaces)
  2. From the archive extract 'Selenium-Server-...' and 'Selenium-dotnet-client-driver-...' into the folder you create in step 1.
  3. Open a command prompt in the 'Selenium-Server-...' folder.
  4. Execute the command 'java -jar selenium-server.jar'
That's it. Your selenium server is now running and waiting for your tests to be executed. Next you'll need to write some tests using your favorite unit testing tool, e.g. csUnit. You'll need to add Selenium's client driver assemblies to your test project. The one you'll need is called 'ThoughtWorks.Selenium.Core.dll' which you can find in the 'Selenium-dotnet-client-driver-...' folder you created earlier. Once adding the required reference writing the test is pretty simple. You can find some examples to start with here.

Saturday, September 05, 2009

Path used in Assembly.LoadFrom()

One way of loading an assembly into an AppDomain is using the static method Assembly.LoadFrom(). An interesting aspect here is: Which folder is used when you supply a relative path? You might be seduced to believing that it will use AppDomain.CurrentDomain.BaseDirectory and combine that with the relative path. That's, however, not correct. Instead it is using Environment.CurrentDirectory, which can be an entirely different directory than the AppDomain's base directory! The online documentation states that it is using "the current directory" but this might still be misleading as it doesn't necessarily make the reader aware that this is different from AppDomain.CurrentDomain.BaseDirectory. Therefore, if you want to be on the safe side construct an absolute path, e.g. by using Path.Combine() etc. Also consider that the location from where you (down)load might actually be an URL.

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.

Saturday, July 25, 2009

Problem using fuslogvw.exe

In case you try to use the Fusion Log Viewer (fuslogvw.exe) and you can't change the Log Settings because they are all disabled then simply run the application as an administrator. To make things really easy just create a shortcut to fuslogvw.exe and modify the shortcut properties (right mouse click). In the "Compatibility" tab tick the box for "Run this program as administrator". Notes:
  • This worked for me using the Windows SDK v6.0A on Vista. It may also work for other versions and other operating system versions but I didn't test that.
  • The Fusion Log Viewer is also known as "Assembly Binding Log Viewer"

Monday, July 13, 2009

Silverlight 3 Tools for Visual Studio 2008

On July 07, 2009, Microsoft published the download for the "Silverlight 3 Tools" for Visual Studio 2008. You can find a short list of what is included in the package and the actual downloads here. Make sure you have Service Pack 1 installed for Visual Studio 2008. Some more stuff to play with!

Friday, June 05, 2009

Background Color of TextBlock in Silverlight 2

In a WPF application (as of .NET 3.5) you can set the background color for a text block as follows:
<TextBlock ... Background="Red" ...> </TextBlock>
Despite being correct Silverlight 2 doesn't like this XAML code. Trying to set it programmatically leads to an exception. Therefore a different solution is needed. Here is what works in my case. I use a Canvas and place a Rectangle and a TextBlock inside of that Canvas. Unless you set the ZIndex use this order so that the TextBlock is in front of the Rectangle. I use the Rectangle as the background for the TextBlock. When the TextBlock changes its size I update the size of the Rectangle accordingly. This solution is pretty simple in the end. First the XAML code:
<UserControl x:Class="Foo.LabelWithBackground"
             Width="200" Height="20">
      <Rectangle Name="_labelBackground" Width="20" Height="20"
         <TextBlock Height="20" HorizontalAlignment="Left" Name="_label"
                    VerticalAlignment="Center" Padding="4,2,4,0" 
                    Text="The Label Text" MinWidth="20"></TextBlock>
Next the C# code-behind:
public partial class LabelWithBackground : UserControl {
   public LabelWithBackground() {
      _label.SizeChanged += LabelSizeChanged;

   void LabelSizeChanged(object sender, SizeChangedEventArgs e) {
      _labelBackground.Width = _label.ActualWidth + 
                       _label.Padding.Left + _label.Padding.Right;
Of course you can use this UserControl in either a page (Silverlight) or in a window (WPF). In both cases you will get a label with background.
Check out my blog on Agile Leadership

Thursday, June 04, 2009

WPF and Silverlight: Sharing User Controls

Both WPF and Silverlight share XAML as the language to describe the layout, look and feel of a user interface. So I thought. There are differences, though, at least for .NET 3.5 and Silverlight 2. And the differences are not only limited to the XAML code but also to the code-behind regardless of whether you use C# or any other .NET language. Sure I did know that Silverlight doesn't support 3D graphics (at the moment) and so I didn't expect those to work. I'm also aware that Silverlight has a Visual Style Manager that is not available in WPF. And the root element in Silverlight is a Page while in WPF it is a Window. And Silverlight is more than just the UI part since it also represents a minimum CLR runtime environment and not a full .NET 3.5 implementation. So my expectations were along those lines. But I discovered more beyond my expectations. Small, yet sufficient differences that makes it hard to share UI components between WPF-based and Silverlight-based applications. And that's what I'd like to do since I want to leave the choice between using a native user interface and a rich internet application (RIA) to my customers. To reduce the gap I'm using I'm using components from the Silverlight tool kit that are in the "stable" band. Otherwise I wouldn't have available components such as TreeView. One example of a noticeable different is that in WPF a TextBlock can have an attribute named "Background" while in Silverlight you will get a parse error of you try to render the XAML code. There are also inconsistencies (or differences) in terms of how mouse events are handled. For instance the set of PreviewMouse* functions that are available in WPF don't exist in Silverlight 2. If you want to use Hittest() in your code-behind it won't work (or even compile) in Silverlight. Instead you have to use functionality of the VisualTreeHelper class. There are quite a few of these difference at the moment and I'll provide more details as I discover them along with code examples. My hope, though, is that over time the differences between the two are reduced at least for the features they have in common. It's pretty annoying that setting the background color is different between WPF and Silverlight. It's also pretty annoying that finding a component at a mouse cursor position is different. Maybe .NET 4.0 and Silverlight 3 are a step towards easier sharing of user controls. The community would love to see that!
Check out my blog on Agile Leadership.

Friday, May 22, 2009

ReSharper 4.5 Memory Consumption

Just tried ReSharper on a fairly large solution with about 38 projects (13 C# and 25 C++). With the ReSharper addin enabled the memory consumption is sitting at about 1.5 GByte for the solution. With the ReSharper addin disabled the memory consumption is sitting at about 300 MByte for the solution. The solution itself has over 90% of its source code in C++ (mix of managed and unmanaged) and only a smaller portion in C#.

JetBrains claim they have worked on the memory consumption of ReSharper 4.5. Looks to me as if more work is needed ....

On my 32 bit box I have to reboot once in a while because I'm running out of memory when the addin is renabled ... (Vista 32 bit, VS 2008, 4 GB RAM)

Update on 04 June 09: It looks as if the memory consumption goes up to the same value with R# disabled. This happens when IntelliSense creates/updates its database. However, with R# disabled the memory drops back to normal once IntelliSense has finished that activity. With R# enabled it appears as if IntelliSense doesn't free up the memory. So it looks as if the problem is caused by the combination of the two. A solution with just C# project (and hence without IntelliSense in C++) doesn't seem to have that issue either.
Since I am in contact with JetBrains at the moment let's see what they can find based on the info I can provide.

Update on 02 February 2010: I had some conversations with JetBrains and they have asked me to provide an example that show the behavior. The challenge is that is seams to happen (or become apparent) only when there is a large number of C++ projects in the solution and the entire C++ code base is significant as well. While I do have an example to demonstrate the behavior, I’m a bit challenged to provide the very example. Would you send your entire code base? At the moment some members of my team have switched off ReSharper when they are working with the solution that also contains C++ projects.

Also check out my blog on Agile Leadership.

Monday, May 18, 2009

A comment on McAfee

Right now McAfee is running a full system scan on my computer. Not only is it consuming a large amount of system resources - sometimes to the point of the system being unusable because of having to wait for some file operation to complete - there is also the following interesting 'feature'. Let's assume a full system scan is running. That seems to make sense since there are many different ways how viruses can find their way onto your computer. So that system scan is running, and you know that it will take an hour or more to complete. You have downloaded a file that you'd like to scan for viruses before you use it. Can you do that? Nope, not with the McAfee version I am currently using. It will display a dialog box telling me a different scan is running and that I have to cancel that one first before I can start a different one. My options are:
  1. Wait until McAfee has finished scanning my system.
  2. Cancel the system scan so I can scan the downloaded file
Option one makes me less productive. Option two has a potential security issue. None of the options meets my requirements. How about being able to explicitly scan files, e.g. from the context menu in the file explorer, regardless of whether other scans are running? I'll check whether other virus scanners work the same way or whether they behave differently. (Before someone asks: Automatic updates to keep McAfee up-to-date are enabled.)

Friday, May 15, 2009

I couldn't resist... - a quote from Subversion's web site

When assessing the memory consumption of the Subversion (SVN) 1.6.1 client, I also found the following on SVN's web site:
"all the memory we allocate will be cleaned up eventually" (Source: "Hacker's Guide To Subversion", retrieved 15 May 2009)
I like that quote since I think it is true for all software! "Eventually" all memory will be cleaned up, and if necessary when the process terminates. On second thought, though, here might be an opportunity for a new business model! What if we had one-way memory? You can allocate it once, and once a process has consumed it you need to buy new DRAM (or maybe it could be called OW-DRAM as in "One Way"-DRAM). I'm sure Intel and other chips vendors would love it! But seriously (and I'm sure I've got some funny things somewhere in my published text and code as well. Tell me!): A memory leak is a memory leak is a memory leak. Using add and commit for adding large amounts of files consumes about 1 KByte per file. In one case I tried to add about 13,000 files and the process fell over when it reached 1.3 GByte having added only 10% of the files. So this approach doesn't work for version 1.6.1. All indications are that this is a memory leak. It is proportional to the number of files you add and try to commit. OS tools show how the process grows in size. It never shrinks (unless the process terminates one way or the other). Admittedly I didn't use a memory profiler, but what do you think the issue is when an error is reported on the command line saying "out of memory"? The better option for getting large sets of files into a repository - and that's what I learned by now - is to use SVN's import functionality. I have made several tests now with up to 65,000 files in one batch (several hundred MB) and the memory consumption of the client process grew only very slowly - from about 10 MB to 58 MB at most. This growth - I suspect - is probably related to memory fragmentation but definitely within acceptable limits. So the recommendation is: Don't use svn add and then svn commit. Instead use svn import if you have large sets of files to import. If they go into the wrong place you can always move them later using a repository browser such as the one that comes as part of TortoiseSVN.

Saturday, May 09, 2009

Handling of middle mouse click in Firefox 3.0

Just had a "experience" of the undesired kind. Normally when you use the middle mouse button on a link in Firefox, it opens the page in a new tab. Well, when you use the middle mouse button on the tab (even when not hitting the little close button) then it closes the tab! Not quite what I expected. I thought it would take the link of what is displayed in that tab and open a new tab with that link. I just lost quite a lot of work that I just had entered into a web form. :-( Oh, well...

Friday, May 08, 2009

SVN Client: Out Of Memory

With the client SVN 1.6.1 (32 bit on Windows) I ran into an issue today. I tried to commit 13,000 files with about 100 MBytes of size. Most of them are text files and just a very small number of them are binary files. No matter what, this commit didn't work. I actually had to take small portions of it and commit one portion at a time. Admittedly this is not a typical change set, and so I don't want to complain too much. There is one observation, though, that made me think: When the client starts to send the content (file data) then the memory consumption goes up. I'm not sure why that is because the file is still available locally (since we are uploading the file) and hence it's not quite clear to me why the consumption needs to go up. The client sends one file at a time anyways. If a buffer is used to get the data into the appropriate format for the wire transmission I can understand that. But can't that buffer be reused once one file has been transmitted and the next one is started? Maybe I'm overlooking something about the inner workings of Subversion. In that case please comment on this post. Otherwise I have that gut feeling that there might be a memory leak in the current implementation (SVN client 1.6.1)? --- An update: There are a few open bugs related to memory leaks, even one with regards to committing large number of added files. That one is from 2004 and still open.

Sunday, April 26, 2009

ListView.GetItemAt() in WPF Application

At present (.NET 3.5 SP 1) a GetItemAt() method doesn't exist for the ListView class that is part of WPF. At least I couldn't find it. I always found it handy in Forms based development for instance when handling mouse events. Please note that the WPF class ListView is in System.Windows.Controls while the forms based class of the same name is in System.Windows.Forms. Don't confuse the two! In this post I'm referring to the WPF class ListView. I wanted a similar behavior to the method of the same name in the forms based library. As a result I want the client code to look like this:
      private void _replacementsListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
         var mousePosition = e.GetPosition(_replacementsListView);
         var item = _replacementsListView.GetItemAt(mousePosition);
         if (item != null
            && item.Content != null) {
            EditTokenReplacement((TokenReplacement) item.Content);
Since the WPF class ListView doesn't come with a built-in method I decided to implement an extension method as follows:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Foo.Gui {
   internal static class Extensions {
      public static ListViewItem GetItemAt(this ListView listView, Point clientRelativePosition) {
         var hitTestResult = VisualTreeHelper.HitTest(listView, clientRelativePosition);
         var selectedItem = hitTestResult.VisualHit;
         while (selectedItem != null) {
            if (selectedItem is ListViewItem) {
            selectedItem = VisualTreeHelper.GetParent(selectedItem);
         return selectedItem != null ? ((ListViewItem) selectedItem) : null;
Please note that the position is passed into the method as an object of class Point. This means that the coordinates need to be relative to the list view object. In an event handler for a mouse button event, e.g. a double click, these can be calculated by using a method on MouseButtonEventArgs object that is passed into the mouse event handler. It's already shown in the first code snippet above but just to be on the safe side here are the relevant lines again:
      private void _replacementsListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
         var mousePosition = e.GetPosition(_replacementsListView); // gets position relative to ListView
         var item = _replacementsListView.GetItemAt(mousePosition);

Saturday, April 25, 2009

Getting Parent Window for UserControl in WPF

Again a small item that may take you some time to search and find on the internet. Suppose you are working on a WPF based application and you have a UserControl that you want to host inside of a window. In addition you need the window within which the UserControl is hosted. To find out that parent window you might wonder whether you could use the property 'Parent'. Well that might work in some cases but in other cases it might not. For example the parent might be a Canvas and then it starts to become tricky. So here is a solution that should make it a bit easier. It uses the static method Window.GetWindow() and passes a reference to the UserControl instance as a parameter:
   public partial class FooControl : UserControl {
      public FooControl() {

      private void _barButton_Click(object sender, RoutedEventArgs e) {
         var window = new MyWindow {
            WindowStartupLocation = WindowStartupLocation.CenterOwner,
            Owner = Window.GetWindow(this)
         if( window.ShowDialog() == true) {
            // Ok button clicked, do something useful here...

Sunday, April 19, 2009

OpenFileDialog in .NET on Vista

I'm working on a WPF based application and as quite some applications do, I need to display an OpenFileDialog as well. Trying to be compliant with what .NET 3.5 SP 1 is offering I tried Microsoft.Win32.OpenFileDialog first. I ran into two issues. The first issue I noted was that the dialog box positioned itself just about anywhere but not centered (or at least on the same screen) as the owner window, even if I set the owner window. I did some research and found that despite .NET having been around for years (I started using it in 2001) there is still no OpenFileDialog box available for .NET that inherits from Window (or Forms previously) and can be easily customized. And therefore - as an example - there is no WindowStartupLocation property. Oh, well ... Even with the latest WPF version running on Vista the old XP style dialog box is displayed: In addition even when I passed the owner as a parameter to ShowDialog() it wouldn't center relative to that owner window. Then I tried the previous System.Windows.Forms.OpenFileDialog(). Although it is not recommended to use that namespace within WPF I thought it would still be worth a try. And voila! Here is the result under Vista: Not only did it display the correct dialogbox under Vista but in addition it's location centered on it's owner is correct as well. To achieve this you have to fiddle a bit with the namespaces as there are a few classes that have the same name in both Microsoft.Win32 and in System.Windows.Forms. Since I wanted the client code to look as simple as possible I created two very small wrapper classes. The first wrapper class is basically a replication of the Microsoft.Win32.OpenFileDialog interface (I left out most of the code since it is simply forwarding):
using SWF = System.Windows.Forms;

namespace FooApp.Presentation {
   internal class OpenFileDialog {
      public OpenFileDialog() {
         _dialog = new SWF.OpenFileDialog();

      public bool? ShowDialog(System.Windows.Window window) {
         return _dialog.ShowDialog(new WindowWrapper(window)) == SWF.DialogResult.OK;

      public string DefaultExt {
         get {
            return _dialog.DefaultExt;
         set {
            _dialog.DefaultExt = value;
      public string FileName {
         get {
            return _dialog.FileName;
         set { _dialog.FileName = value; 
      public string Filter {
         get {
            return _dialog.Filter;
         set {
            _dialog.Filter = value;
      public string Title {
         get {
            return _dialog.Title;
         set {
            _dialog.Title = value;

      private readonly SWF.OpenFileDialog _dialog;
The only really interesting piece is the ShowDialog() method which takes a WPF window. System.Windows.Forms.DialogBox.ShowDialog() requires a IWin32Window instead (for easy access to the window handle), so we need a second wrapper class that looks as follows:
using System;
using System.Windows;
using System.Windows.Interop;

namespace FooApp.Presentation {
   /// <summary>WindowWrapper is an IWin32Window wrapper around a WPF window.
   /// </summary>
   /// <remarks>Add System.Windows.Forms to the references of your project to
   /// use this class in a WPF application. You don't need this class in a
   /// Forms based application.</remarks>
   internal class WindowWrapper : System.Windows.Forms.IWin32Window {
      /// <summary>
      /// Construct a new wrapper taking a WPF window.
      /// </summary>
      /// <param name="window">The WPF window to wrap.</param>
      public WindowWrapper(Window window) {
         _hWnd = new WindowInteropHelper(window).Handle;

      /// <summary>Gets the handle to the window represented by the implementer.
      /// </summary>
      /// <returns>A handle to the window represented by the implementer.
      /// </returns>
      public IntPtr Handle {
         get { return _hWnd; }

      private readonly IntPtr _hWnd;
With this machinery in place the client code in a WPF based application looks very familiar and simple:
var dialog = new OpenFileDialog {
   DefaultExt = ".dll",
   Filter = "Assemblies (*.dll; *.exe)|*.dll;*.exe",
   Title = "Select Assembly"
if( dialog.ShowDialog(this) == true ) {
   // File is selected, do something useful...
As a result you have it all, simple client code, the correct OpenFileDialog on Vista and the dialog centered properly on its owner. The only thing that I still can't get my head around: After 8 years of .NET we still don't have a class available that is based on Window (or Form) and can be customized. It seems as if this is a puzzle that the guys in Redmond haven't figured out yet...

Wednesday, April 15, 2009

Separator for Menu Item in XAML (WPF, Silverlight)

Trivial task and yet worth mentioning: You want a separator in your XAML based application (WPF or Silverlight)? Use System.Windows.Controls.Separator. In XAML write as follows:
<Menu ...
  <MenuItem ...
     <MenuItem ...
     <Separator />
In C# use:
using System.Windows.Controls;

Menu menu = new Menu();
menu.Items.Add(new Separator());

Tuesday, April 14, 2009

LinearGradientBrush with more than two GradientStop's in XAML

Using Expression Blend 2 you may believe that you can have only two GradientStop's for your LinearGradientBrush in particular if you are UI addicted as I am. The UI of Expression Blend 2 doesn't offer adding another GradientStop. But funny enough it supports them! So just go to the XAML code for, e.g. select "View XAML" from the context menu and just add another GradientStop tag to the XAML code for the GradientBrush. Once you do that you will notice that the Expression Blend 2 user interface will happily display 3 (or more) sliders as demonstrated in the screenshot. Here is an example:
<lineargradientbrush key="WindowBackgroundBrush"
  spreadmethod="Pad" endpoint="0.5,1" startpoint="0.5,0">
<gradientstop color="#FFFFDCDC" offset="0.56" />
<gradientstop color="#FFFF6F6F" offset="0.77" />
<gradientstop color="#FFFFDCDC" offset="1" />

Monday, April 13, 2009

TextBox and other Controls with Transparent Background in XAML

Again a small item but something you may have searched for quite a while. In a XAML based user interface (WPF, Silverlight) if you want your control (e.g. TextBox) to NOT have a background, that is you want the background to be transparent you can do one of the following:
  1. Set its Background property to 'Transparent'
  2. In Expression Blend select the Background brush and set the alpha channel to zero
Sounds simple but it might take you longer than expected to find this information on the internet (unless I'm completely hopeless to enter the appropriate keywords). Most sources explain for the 100th time how to set the background color.

Sunday, April 12, 2009

"The file 'x' is not part of the project or its 'Build Action' property is not set to 'Resource'"

When working on a WPF based application and using the Image control you may encounter the following error message when trying to enter the source file name for the image:
The file 'x' is not part of the project or its 'Build Action' property is not set to 'Resource'
It's not quite clear to me what causes this and it's not quite clear why Microsoft didn't fix it in Service Pack 1 for Visual Studio 2008 but here is a solution that may work for you:
  1. Add the file to your solution.
  2. Set its 'Build Action' to 'Resource' (in my case the drop-down also offers 'Embedded Resource' but that's not what you want)
  3. Select the image control.
  4. Set its Source property to the image file name. It should show up in the drop-down list. Next it may display the error message mentioned above. Then rename the image file to a short filename. Try setting the Source property of the Image control again. It should be fine now.
In case you want to try editing the XAML code then here is an example of what you may want set the source property to:
<Image ... source="Foo.Gui;component/pictures/myLogo.jpg" ... />
The assumptions for this example are
  • Your project is named 'Foo.Gui'
  • That project contains a folder named pictures
  • Your picture is in that folder and also included in the project. The name of the picture is 'myLogo.jpg'

Saturday, April 04, 2009

"Configuration system failed to initialize"

If you see a ConfigurationErrorsException along with the information "Configuration system failed to initialize" in your QuickWatch window then in all likelihood your app.config (or web.config) file is not correct. In my case I simply forgot to surround the membership provider section with <system.web></system.web>. Once I added those it worked like a breeze. Also, in case your custom provider cannot be found, make sure you have added the proper assembly name to the 'type' attribute for the <add> element of your provider in the <providers> section. And yes, you can test custom providers without having to deploy to or run in a web server. Just ensure your app.config file contains the bare minimum by copying some content from web.config and you should be fine. For my scenario it was sufficient to copy the config section for NHibernate, the hibernate configuration, and the declaration for my custom membership provider.

Friday, April 03, 2009

Membership Provider Implementation using NHibernate

ASP.NET allows selectively replacing provider implementations with your own custom implementation, e.g. when you want to store membership information in a database other than aspnetdb.mdf. There are more details provided on MSDN. Microsoft provides one such example implementation for ODBC in C# here. For VB.NET a sample membership provider implementation can be found here. While the provider concept is essentially nothing more than Microsoft's flavor of service trays, it is not a surprise that by default Microsoft has a preference for their own products, in particular Microsoft SQL Server. And as long as you don't have a good reason to get into the details of a custom implementation it probably is a good choice to go with what comes out of the box. However, I (and my customers) would like a little more flexibility. Since I'm also experimenting with Fluent NHibernate I am attempting to implement a custom membership provider for ASP.NET based on NHibernate. The idea is that I could use in-memory databases for testing and SQL Server or PostgreSQL for production without having to change a single line of code. All I would need is changing four lines in web.config. So goes the theory. Let's see whether practice proves it right. So far the code looks much simpler than the ODBC sample implementation and yet easier to read and understand. I'll keep you posted.

Saturday, March 28, 2009

csUnit 2.6 Released

csUnit 2.6 has been released and is available for download. More information is available here. The major points of interest are:
  • csUnit is now based on .NET 3.5 SP 1
  • Parameterized testing moved out of experimental
  • Basic support for Microsoft unit testing.
  • Several bug fixes.
csUnit 2.6 supports the following unit testing frameworks:
  • csUnit (no surprise!)
  • NUnit 2.4.7 (.NET 2.0)
  • Microsoft Unit Testing (basic support)
When executing MSFT based tests no files (except the XML results file were applicable) is generated. This means improved performance in some cases and reduced disk space requirements. Please note, that csUnit does not ship with the framework assemblies for NUnit and MSFT Unit Testing. csUnit, however does not require any of those assemblies to run. So if you use only the csUnit testing framework you can safely ignore that csUnit supports other framework as well. There is increasing interest in a 64 bit version and we are looking into that option. We have also some more ideas with regards to integrating csUnit with other tools. In addition we are taking a very tough look at the usability of the tool since we feel that there are opportunities for improvement in this area as well.

Friday, March 20, 2009

"Failed to create a service in configuration file"

You may encounter this error message when you try to add a WCF base service to your web service project. The additional text of this error message is: A child element named 'service' with same key already exists at the same configuration scope. Collection elements must be unique within the same configuration scope (e.g. the same application.config file). Duplicate key value: 'FooProject.BarService'. The cause for this error message might be that you added a service to your project with the same name previously, then deleted it again. The remnants of that deleted service prevent the new service with the same name to be created. To resolve the problem do this:
  1. In the web.config file locate the XML node within the node . For instance in the above example locate the node that describes the 'BarService'. Delete that node but leave in the file.
  2. In the same file locate the node with an attribute 'behaviorConfiguration' and an attribute value of 'BarService'. This node also contains the endpoints for the service. Remove this node.
  3. Try again, and this time it should work.
This is not a major problem but shows that a wizard for adding a service isn't necessarily coupled with an according wizard to remove the service in case you changed your mind. Removing means deleting the BarService.svc and its implementation file, e.g. BarService.svc.cs. It doesn't, however, delete the related entries from the web.config file.

Thursday, March 19, 2009

Updating Silverlight User Interface From Timer

Updating a Silverlight based user interface from a timer may not work as expected. The reason is that the timer thread is different from the user interface thread. Only the user interface thread can update a Silverlight based user interface. So for instance the following code will not work in a Silverlight application:
// _statusMessage is a System.Windows.Controls.TextBlock object
// _statusMessageTime is a System.Threading.Timer object
private void DisplayStatusMessage(string message) {
  _statusMessage.Text = message;
  _statusMessageTimer = new Timer(ResetStatusMessageCallback,
                            /* params left out for brevity */);

private void ResetStatusMessageCallback(object stateInfo) {
  _statusMessage.Text = "";
When the timer fires the callback is executed on a thread different to the user interface thread. The UI will not update. In my installation the Silverlight interface would then simply disappear! To fix this you need a way to execute the actual update on the user interface thread. One way is to use the Dispatcher object (Namespace: System.Windows.Threading) of the XAML page. Then the code of the callback implementation looks as follows:
private void ResetStatusMessageCallback(object stateInfo) {
  Dispatcher.BeginInvoke(() => {
                         _statusMessage.Text = "";
Another solution would be to use the DispatcherTimer. I spare you the details but you can check here for an example.

Monday, March 16, 2009

ClassInitialize Method Can Be 'static'

A few days ago I wrote about adding support for MS Unit Testing to csUnit (see here). Since I am also using ReSharper it sometimes suggests declaring methods as 'static' when the code of the method doesn't access any instance variables. So just now it happened that a method marked with the 'ClassInitializeAttribute' was marked as static as well. When executing the set of tests in this class the method with the 'ClassInitializeAttribute' wasn't executed at all because apparently csUnit wasn't picking it up. So I went and checked the csUnit code and found that the equivalent FixtureSetupAttribute was found only for non-static methods as well. So at least that was consistent. Giving it a second thought I decided that it definitely makes sense to allow the FixtureSetupAttribute (and consequentially the 'ClassInitializeAttribute') to be on static methods as well. However, that isn't quite that straight forward the way the scanners in csUnit are implemented. So I'll have to do some refactoring before support for static fixture setup methods becomes available in trunk (let alone in a future release). So that would bring the list of supported MS Unit Testing attributes to the following:
  • TestClassAttribute
  • TestMethodAttribute
  • ExpectedExceptionAttribute
  • ClassInitializeAttribute
Assertions are supported anyways. The support of MS Unit Testing in csUnit is making progress.

Sunday, March 15, 2009

Implicit Typing Can Make TDD Harder

Starting with C# 3.0 the language supports the concept of implicit typing at the method level using 'var'. While on one hand this new keyword has its benefits such the possibility to change return types of methods without having to change the type of all local variables that the return value is assign to, there is also a draw back of this new language feature. If you are using strict TDD, you write your tests to drive your design. That means it is not uncommon that a new method on a class doesn't exist yet, though you can write your test including assertions on the return type. Example:
public class Result {
   public long Status { get; set; }

public class Foo {
Given this starting point you may want to write the following unit test to ensure that class Foo requires a method 'Result NewMethod()':
public void TestNewMethod() {
   var foo = new Foo();
   var result = foo.NewMethod();
   Assert.AreEqual(0, result.Status);
As you type you will notice that when you have typed the dot after 'result' you will not be offered the member list of Result. It's not possible to implicitly type the variable 'result' since the method 'NewMethod()' doesn't exist yet. As a result writing tests in a TDD approach is slowed down when using 'var' instead of explicit types. Here is another view you may take: Writing tests for 'NewMethod()' should include all specifications, including the type of the return value. If you agree with that view you may want to avoid using 'var' in your unit tests. This certainly doesn't apply to people who create their unit tests after the method has been added to the class. I personally wouldn't call this test-first development, let alone test-driven development (or test-driven design as some people argue). Bottom line it depends on where you are coming from. 'var' might not always be the best choice even if it is a new 'cool' feature in C# 3.0.

Saturday, March 14, 2009

Passing Serialized Exceptions as Service Faults

One way to pass errors from methods back to a caller is using Exceptions. Unfortunately that doesn't work with services since a caller might be anything and so you shouldn't assume that the client understands the .NET platform (and in particular WCF) as well. Therefore in a service oriented world operations return faults. When implementing a service with WCF you could use the FaultContract() on your service operation. In addition you can also use the ExceptionShielding Attribute on your service implementation. However, ExceptionShielding along with includeExceptionDetailInFaults in the service configuration covers unknown and unhandled exceptions only. Other exceptions are mapped to faults, and that's where your responsibility comes in. Whatever you return to a caller, provide as little information about what happened as possible. For instance you may log an exception to a log file on the server hosting the service and attach a case id to it. Then return that case id as part of the service fault. To get more details about a fault this case id can be used to locate the detailed information in the log file. One thing you definitely shouldn't do is passing the entire exception including call stack in a textual or serialized format to the caller. You don't want to add that additional security risk. The reason you don't want to include too much information in the fault is that an attacker might be able to use the details for future attacks. You don't want to present that information on a SilverPlatter. So for instance you could use the following class for representing faults:
using System.Runtime.Serialization;

namespace AgileTraxx.Services {
 public class ServiceResult {
    public ServiceResult(string message, long incidentId) {
       Message = message;
       IncidentId = incidentId;

    public string Message { get; set; }

    public long IncidentId { get; set; }
This class would just take the incident id plus a message. The message could contain information about how to contact support and to note down the incident id. As you can see there is a lot to consider when designing a service interface, including security related factors.

Sunday, March 08, 2009

Service Reference for method returning void and out parameter

The title is quite lengthy but I couldn't find a better one. In essence I'd like to make describe a little catch you might experience when generating a service reference within Visual Studio 2008 (it might apply to other versions as well). Suppose you have a service implemented in WCF (Windows Communication Foundation). The services exposes an operation as follows: void UpdateItem(ItemData data, out ServiceFault fault); (Yes, I know that faults should be handled differently but if you want to support Silverlight there are not too many alternatives at present since we are running inside a browser. I wrote about this before so won't go into details here.) Note that the class ServiceFault is a very simple class. The details are not relevant here. The point I want to make here is this. When you create a service reference to the service that provides the above the operation Visual Studio will generate the signature in the service client as follows: public ServiceFault UpdateItem(ItemData data); You will notice that the return value has change from void to ServiceFault, and that the new operation takes only one parameter and has no out parameter. While generally it is probably a smart assumption that for a void operation the first (or only) out parameter is turned into the return value you may not want this in all cases. For some users this behavior might even be surprising. It might make sense to argue that this is a violation of the principle of least surprise. In my particular case I wanted the signature to be consistent with other signatures from other operations in the same service. So I changed the service interface to: long UpdateItem(ItemData data, out ServiceFault fault); The implementation always returns 0 as a result. And now, when I update the service reference I get the expected matching signature generated, and all signatures for the operations within my service are now consistent. On second thought, though, I might actually try a different approach. What if the return value becomes of type ServiceResult? And if I actually have to return some values these can always become an out paramter. I'll give that thought a try and keep you posted.

Thursday, March 05, 2009

Domain Objects with Validation in Fluent NHibernate

Here is an issue that took me quite some time to figure out how to resolve it. I am experimenting with Fluent NHibernate. My starting point was that I wanted the code of my domain classes squeaky clean: Not a single hint that they may become persistent. Why? I wanted to have the domain free from anything that has nothing to do with the domain. At the same time I wanted the domain model to contain the validation code. Ok, I know the way I implemented validation is not necessarily in line with the usual approach in NHibernate. But let's have a look at my domain class:
   internal class WorkItem {
      public WorkItem () {

      public virtual long Id {
         get {
            return _id;
         set {
            _id = value;

      public virtual string Title {
         get {
            return _title;
         set {
            _title = Validation.EnsureNonEmptyString(value, "Title");

      private long _id;
      private string _title = "";
I left most of it out. For now let's look at just the id and the title since those two demonstrate sufficiently the issue. What you will notice is that the setter for the title contains validation code ("Validation.EnsureNonEmptyString(...)"). The problem starts when you query for one or more WorkItem's. Then NHibernate will use the property setters to initialize the instance of WorkItem. For strings the default value is null (nothing in VB.NET). With the given code, however, the validation will throw an exception since that is what it is designed to do. It doesn't care whether the setter is called by NHibernate or anything else. So next I tried to figure out what alternatives I would have for validation and I found NHibernate.Validator. Although a step in the right direction I didn't like that the client code for the domain objects would have to explicitly call the validation. Alternatively the validation would have to be invoke via the event call backs from NHibernate. In both cases the domain class would only work properly if something else would collaborate. I didn't like that concept and started to look for an alternative. And there is a quite simple solution to this: Change the configuration for NHibernate so that it doesn't use the properties to initialize the domain objects. This configuration change can be done via Fluent NHibernate as follows:
       _hibernateConfig = new Configuration();
         AutoPersistenceModel persistenceModel = 
               map => map
Depending on your naming conventions you may want to use a different access strategy or a different Prefix value. In my case it was Camel Casing with an underscore as a prefix. After I finally found this solution I was able to keep the domain classes squeaky clean and at the same time stay with using the Fluent NHibernate interface and avoiding exception during the initialization of instances of domain classes. Of course I'm not sure whether this is the only and/or best option. If you have other options that are even better, please drop me a note. I'm always keen to learn more!

Tuesday, March 03, 2009

Executing MS Unit Tests in csUnit

I have made a little progress on the MS Unit Test support in csUnit. So far I managed to create support for:
  • TestClass
  • TestMethod
  • ExpectedException
Admittedly, these are just the most basic ones but it is a start. Next, I'll have to do some refactoring to clean up the code. As of now, csUnit can execute tests implemented using the unit testing frameworks of either csUnit, NUnit, or MS Unit Test. (Note: This is in trunk as of now. No release is available yet.)

Monday, March 02, 2009

Another Tool for Silverlight Unit Testing

Just came across another unit testing tool for Silverlight. It's called SilverUnit. I haven't tried it out but I certainly will have a closer look. It will be interesting to see how this compares to Jeff Wilcox's approach and how it integrates with established unit testing tools. I'll keep you posted.

Sunday, March 01, 2009

csUnit migrated to .NET 3.5 and VS 2008

Finally I have found some time again to do a few things on csUnit. Actually the main driver was that I tried out the unit testing features that come out of the box with Visual Studio 2008 and I found them a little bit too cumbersome for my taste. I'm sure there are scenarios, teams, and people who are looking exactly for what VS's unit testing provides, including the ability to look at old test runs. But overall it felt a little bit too heavy. One example. A test fails. The result's view lists all tests and you can click on the one that failed. But it doesn't bring you straight to the failed test. That was my expectation. Instead it brings you to a page with the result details of that test. And only there you find a link to the actual implementation of the test. Conceptually that's probably what MSFT wanted. For me it felt like being slowed down. So now I've moved csUnit to .NET 3.5 and migrated the solution and all projects within it to VS 2008. And I'm looking into making it possible for csUnit to run tests implemented using MSFT's unit testing framework. Let's see how that goes. One difficulty I already discovered: Counting assertions. I don't have a good solution for that yet but if you do, please let me know!

Saturday, February 28, 2009

Designing Service Interfaces For Silverlight Clients

When designing a service interfaces based on WCF you might be considering indicating service errors via service faults. By and large that might be a good choice but in the case of Silverlight clients consuming that service you may want to read Eugene's blog first. Eugene describes very detailed the technical background for why a Silverlight client running in a web browser may not be able to see the fault with all details. He also provide a few suggestions for how to get around that limitation - which is not Silverlight's fault! - including code examples. In some cases have a separate set of services for Silverlight client's might be an option worth exploring as well. That way you can give service clients, which are not hampered by browser's 'filtering', the best possible experience.

Saturday, February 14, 2009

Parser Error Message: Could not load type 'Global'

If you get an error as follows: "Parser Error Message: Could not load type 'Global'" then you may be able to fix this issue by doing the following:
  1. Open the file containing your class Global typically located in the file Global.asax.cs,
  2. Note the namespace for that file
  3. Open the file Global.asax
  4. Locate the line that contains the element "... Application Codebehind=..."
  5. In that line ensure that the element "Inherits=..." includes the namespace for your Global class, e.g. MyWebSite.Global, (Inherits="MyWebSite.Global"). Replace MyWebSite with the namespace noted in step 2
  6. Recompile and redeploys.
  7. The error should be gone.
Note that this post applies to VS2008 and ASP.NET using .NET 3.5. The web site in question hosted web services only. This post may not work for other scenarios or for other root causes.

Tuesday, January 13, 2009

Unit Testing for Silverlight

Looking for instructions for Unit Testing for Silverlight 2? Jeff Wilcox posted an excellent tutorial in March 2008 here. Since then he's also updated his testing framework. In addition he has posted required changes to make the tutorial work with the final release of Silverlight 2. Although the latter post refers to RC0 of the testing framework the information still applies to the December 2008 binaries. The December 2008 release of the binaries of Jeff's unit testing framework can be downloaded from here. The project's homepage is here.