Saturday, February 27, 2010

ReSharper 4.5 Memory Consumption – Hopefully The Last Post On This Subject

I posted in the past about the memory consumption of ReSharper 4.5 with large solutions containing C# but also many C++ projects with over one million line of codes. We installed at least one newer patch in the meantime and it seems that the memory consumption issue caused by the combination of IntelliSense and ReSharper has disappeared in that once IntelliSense has built it’s cache, memory consumption goes back to normal.

In other words the guys at JetBrains seem to have found something, so this issue is solved for the time being. Some of my team members have switch ReSharper back on since.

But there is more admittedly smaller things. One of them is that updating the namespace for a class removes comments from the source code if those comments happen to be in the “wrong” location. Example: Create a WCF library. It will generate a service as an example in that project. Then set the default namespace in the project file to a different value. Go back to the service files (interface and implementation) and use ReSharper to move the interface and the service to the new updated namespace. One comment will disappear in each file. The generated comment is not a big deal. But it could also be a comment that you wanted to keep, let’s say a URL with important background details of your implementation. This behavior is reproducible with version 4.5 and Visual Studio 2008. I haven’t checked the beta for version 5.0, though. Chances are that this has been fixed as well.

Don’t get me wrong: ReSharper is a tool that helps improving the productivity and quality of your code significantly. Despite a few nuisances in the product I use ReSharper on a daily basis. Whether you use this tool or a different one, there is no excuse for not refactoring your code mercilessly!

Tuesday, February 23, 2010

Generic Empty Array

In certain situations empty arrays of a specific type can be handy. Of course you could always use “new MyType[0]” to instantiate such an empty array and in most situations this will be just fine.

However, if this happens often – like hundreds and thousands of times – then you may want to consider the implementation of a generic empty array. Although it consumes only a few bytes per instance it still contributes to memory consumption and fragmentation and the garbage collector has a few more things to do as well. With a generic empty array a single instance per type is shared throughout your code and those –generally small problems – are avoided in the first place.

Of course this idea is not new. For example check out this conversation on stackoverflow. However the code given there contains a small glitch and doesn’t compile, so here is the source code for the same thing with that glitch resolved:

   25 namespace csUnit.Common {

   26    public static class EmptyArray<T> {

   27       private static readonly T[] Empty = new T[0];

   28       public static T[] Instance {

   29          get { return Empty; }

   30       }

   31    }

   32 }

But wait, there is one more: When you use an array as a return value for a method you may also want to consider reading Eric Lippert’s thoughts on the subject. It definitely doesn’t hurt and may make your code more efficient and improve the design of it.

Friday, February 19, 2010

Whereabouts of csUnit

Ok, I’ve been a bit quiet on csUnit for a while. The reason being that I tried to get a plug-in for ReSharper running. And to some degree I got it to where the most simplest cases would work. At the moment I’m kind of stuck. I tried to figure out how to make it execute SetUp, FixtureSetUp, etc. methods but wasn’t successful so far. I tried to find some online documentation, got the sources for about half a dozen other plug-ins, and still. Maybe I’m just overlooking something very obvious.

So any of you, dear readers, if any of you can point me to more information or if anyone would like to help out, please get into contact at manfredmlange at gmail dot com. Thank you!

Of course I’ll continue searching for a solution in the meanwhile but I cannot make any promises.

Tuesday, February 16, 2010

Consuming a WCF Service

In one of my recent posts I demonstrated how to implement a simple WCF service using Visual Studio 2008. This time I’ll look at how to implement the client. In doing so I’ll highlight an important oversight of quite a few examples on the internet include at least one provided my Microsoft (see references)!

I’ll continue where I left the solution last time:

image

I’ll add a service client next. Many different options are possible, a Forms-base native application, a WPF-based client, an ASP.NET site, command line, and many more. For this example I’ll use an ASP.NET front-end.

Creating the ASP.NET Application

I’ll use add a new project to the solution. Here is the recipe:

  1. Select from the solution context menu “Add”, then “New Project…”
  2. In the tree on the left expand the “Visual C#” node, then click “Web”
  3. On the right select “ASP.NET Web Application”
  4. As a name enter “DuckWeb”.

Here is how it should look like just before you click “OK”:

image Click OK and your solution should now look like this (I collapsed the DuckServiceLibrary to save some space):

imageOpen the file Default.aspx in source mode and add a label, a text box and a button as follows:

    1 <%@ Page Language="C#" AutoEventWireup="true"

    2     CodeBehind="Default.aspx.cs" Inherits="DuckWeb._Default" %>

    3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    4          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    5 <html xmlns="http://www.w3.org/1999/xhtml" >

    6 <head runat="server">

    7     <title></title>

    8 </head>

    9 <body>

   10     <form id="form1" runat="server">

   11     <div>

   12     <asp:Label ID="_pondNameLabel" runat="server" Text="Pond Name:">

   13     </asp:Label>

   14     <asp:TextBox ID="_pondNameTextBox" runat="server"></asp:TextBox>

   15     <asp:Button ID="_submitButton" runat="server" Text="Submit"

   16           onclick="_submitButton_Click" />

   17        <br />

   18        <br />

   19        <asp:Label ID="_pondStatusMessage" runat="server" Text="Status unknown.">

   20        </asp:Label>

   21     </div>

   22     </form>

   23 </body>

   24 </html>

When you view this in a browser it looks like this:

image

It doesn’t do anything yet, however. Next I’ll add an event handler to clicking the button. In the Design view of Visual Studio for Default.aspx I simply double-click the button which gives me the following handler:

   14 protected void _submitButton_Click(object sender, EventArgs e) {

   15 

   16 }

In this I’ll add the the code for the service. However, in order to consume the service the web application needs a reference to it. That’s easy to do by doing a right mouse click in the solution explorer on the project “DuckWeb” and then selecting “Add Service Reference…”:

imageIn the “Add Service Reference” dialog I click the “Discover” button and then enter as namespace at the bottom “PondServiceReference”:

image

Upon clicking “OK” the service reference will be added and I can start using the service as if it was just another .NET library.

image Let’s return to the _submitButton_Click() event handler. Since I now have the service reference available I can write my first implementation:

    1 using System;

    2 using System.Web.UI;

    3 

    4 using DuckWeb.PondServiceReference;

    5 

    6 namespace DuckWeb {

    7    public partial class _Default : Page {

    8       protected void Page_Load(object sender, EventArgs e) {

    9 

   10       }

   11 

   12       protected void _submitButton_Click(object sender, EventArgs e) {

   13          var client = new PondServiceClient();

   14 

   15          _pondStatusMessage.Text = _pondNameTextBox.Text +

   16             (client.IsFrozen(_pondNameTextBox.Text) ?

   17                                     " is frozen." : " free of ice.");

   18       }

   19    }

   20 }

Note that I added a using statement for the namespace that contains the generated classes for the service reference. Please also note that this code is far from production ready but I’ll come back to this shortly. First let’s see whether this already works as expected. After setting the DuckWeb project as the startup project the browser is launched and I give it a test run:

image Just what I wanted! So all good, right? Not quite! Return to the code where I create the PondServiceClient instance:

   13 var client = new PondServiceClient();

In this line I also create a connection to the service. However, nowhere in the remainder of the code do I close this connection. Of course at some point the instance will be subject to garbage collection and of course the connection will eventually be closed. However, if I rely on this mechanism I have very little control over when that happens. In this simple example it may not be a big issue. However, if the service implementation uses other resources per connection, e.g. a database connection, or if the service is configured to service only a certain number of open connections, e.g. 10, then your system will get into trouble very quickly. Unfortunately some examples on MSDN or similar sites don’t close WCF connections either (see references below), so chances are that we’ll see service clients that won’t be implemented correctly.

Therefore let’s add a line that closes the connection:

   13 protected void _submitButton_Click(object sender, EventArgs e) {

   14    var client = new PondServiceClient();

   15 

   16    _pondStatusMessage.Text = _pondNameTextBox.Text +

   17                              (client.IsFrozen(_pondNameTextBox.Text)

   18                                  ?

   19                                     " is frozen."

   20                                  : " free of ice.");

   21    client.Close();

   22 }

Now this looks already better. But it is still not good enough!

What if we cannot connect to the service for whatever reason? If that is the case the generated code will throw different types of exceptions depending on the error. The recommended way (or canonical way if you like) of handling the exception looks as follows:

   23 protected void _submitButton_Click(object sender, EventArgs e) {

   24    var client = new PondServiceClient();

   25 

   26    try {

   27       _pondStatusMessage.Text = _pondNameTextBox.Text +

   28                                 (client.IsFrozen(_pondNameTextBox.Text)

   29                                     ?

   30                                        " is frozen."

   31                                     : " free of ice.");

   32       client.Close();

   33    }

   34    catch (CommunicationException ex) {

   35       // Handle exception

   36       client.Abort();

   37    }

   38    catch (TimeoutException ex) {

   39       // Handle exception

   40       client.Abort();

   41    }

   42    catch (Exception ex) {

   43       // Handle exception

   44       client.Abort();

   45    }

   46 }

In all exception handlers I call client.Abort() to cancel the connection. In a real application I would also present a message to a user along the lines “Cannot answer your request as a required service is temporarily not available. Please try again later.”

How about using a using(var client = new PondServiceClient()) contruct:

   49 protected void _submitButton_Click(object sender, EventArgs e) {

   50    using(var client = new PondServiceClient()) {

   51       _pondStatusMessage.Text = _pondNameTextBox.Text +

   52                                 (client.IsFrozen(_pondNameTextBox.Text)

   53                                     ?

   54                                        " is frozen."

   55                                     : " free of ice.");

   56    } // Dispose will be called here.

   57 }

Dispose will be called at the end of the using-block. However, this code doesn’t handle the exceptions yet that you might encounter in the invocation of the service. Furthermore, an exception can also happen when Close() is called from Dispose(). How would you handle those exceptions? The using-construct would lead to very ugly code. For a more detailed discussion see the references at the end of this blog.

This concludes this step of the blog post series on WCF services. There will be at least one more on how to propagate error conditions from a service to a consumer.

Update 09 April 2012: In a newer blog post I’m discussing various options for simplifying the client side. The discussion includes ways for handling everything according to Microsoft’s recommendations while at the same time avoiding code duplication.

References

Some examples for WCF client code that doesn’t close the connection to the service:

It is correctly mentioned and demonstrated at:

Friday, February 12, 2010

Installing SQL Server 2008 (64bit) on Windows 7 (64bit)

As described here you can run into an error when trying to install Microsoft SQL Server 2008 (x86, 64bit) on a Vista (64bit). The error message is something along the line "The INSTANCESHAREDWOWDIR command line value was not specified. This value must be specified when the INSTANCESHAREDDIR value is specified."

You can run into the same issue on a Windows 7 (64bit) as well as I had to learn today. I used the default installers for SQL Server 2008 Developer Edition, 64 bit.

One additional note, though: If you have accidentally changed the default installation path to something that works for you and then back to the default, the error might not go away. In that case cancel the installation and start all over. This time, don't touch the default installation path.

This approach worked in my case. Of course, if you prefer the software to be installed in a different location or drive, you may have to try the workaround described here.

Thursday, February 11, 2010

Microsoft Visual Studio 2010 RC Released

Microsoft just made available the release candidate (RC) for Visual Studio 2010 and the .NET Framework 4.0. The downloads are available for non-MSDN subscribers as well. The RC does not support Silverlight 4 development. If this applies to you stay on beta 2.

Thursday, February 04, 2010

Using Environment Variables in WiX

Today I ran across a challenge with WiX, which took me a couple of hours to resolve. Maybe I can help you saving this time by describing what I tried to achieve and how I resolved it in WiX.
Although our build machine uses a 32 bit operating system in some cases we build certain solutions on a 64 bit OS. One of these solutions includes a WiX project which packages a merge module for the C runtime libraries. On the 32 bit platform merge modules are located in “c:\Program Files\Common\Merge Modules”. In our WiX installer script (a WSX file) we package a merge module with a hardcoded path. This works fine on a 32 bit operating system.
However, it fails on a 64 bit operating system. There Visual Studio 2008 places the merge modules in “c:\Program Files (x86)\Common\Merge Modules”. As a consequence the hard code path doesn’t work.
I’d like to do set this path differently based on an environment variable. I chose “CommonProgramFiles(x86)” which exists on the 64 bit platform but is undefined on a 32 bit OS. Based on information I found at WiX’s web site, my first attempt looked as follows:
    3 <?ifdef $(env.CommonProgramFiles(x86)) ?>
    4 <!-- Variable is defined, we are building on 64 bit -->
    5 <?define commonProgramFiles = "c:\Program Files (x86)\Common\" ?>
    6 <?else?>
    7 <!-- Variable is not defined, we are building on 32 bit -->
    8 <?define commonProgramFiles = "c:\Program Files\Common\" ?>
    9 <?endif?>
Note, that this is not about the computer on which I want to install the software package. This is about the computer on which the installer is created. So the idea is that I would then be able to use the variable ‘commonProgramFiles’ later in the script, e.g. when referencing a file:
    1 <File Source="$(var.commonProgramFiles)Merge Modules\Microsoft_VC90_CRT_x86.msm" >
    2    ...
    3 </File>
Trouble was that it wouldn’t work. With some further digging I found a message in an email list that contained the helpful hint. The relevant quote is:
“Use <?ifdef?> first to see if it's defined. Don't use $() around it in an <?ifdef?>.”
So I rewrote the the WiX script as follows:
    3 <?ifdef env.CommonProgramFiles(x86) ?>
    4 <!-- Variable is defined, we are building on 64 bit -->
    5 <?define commonProgramFiles = "c:\Program Files (x86)\Common\" ?>
    6 <?else?>
    7 <!-- Variable is not defined, we are building on 32 bit -->
    8 <?define commonProgramFiles = "c:\Program Files\Common\" ?>
    9 <?endif?>
Note how line 3 has changed. Now it worked like a breeze! I can now build the installer on both a 32 bit OS and a 64 bit OS and the project will still find the required merge module.
One further note: If you want use any of the WiX tools in a batch file, you may want to use %WIX% instead of a hard coded path to the toolset.
Jason, thank you very much for your help in sorting this out!
P.S. I haven’t forgotten about the mini-series of blogs about WCF-based services I’ve started a few days ago. It’s still coming!

Wednesday, February 03, 2010

ArgumentException vs ArgumentNullException

Ok, maybe I’m missing the point, but here is an item I don’t understand: When you want to throw an ArgumentException with the parameter name and a message as arguments, then the parameter name is the first parameter. When you use ArgumentNullException it’s just the other way round. Sounds complicated? It becomes more apparent once we look at some source code:

    1 public void DoSomething(string paramName) {

    2    if (paramName == null) {

    3       throw new ArgumentNullException(

    4          "paramName", // Must be first parameter here

    5          "Parameter cannot be null."

    6       );

    7    }

    8    if (paramName.Length < 10) {

    9       throw new ArgumentException(

   10          "String must have at least 10 characters.",

   11          "paramName"  // Must be second parameter here

   12       );

   13    }

   14    // ... rest of the method ...

   15 }

I haven’t noticed this in the past but nevertheless: Unless I’m totally overlooking the brilliant idea behind this, I’m not quite sure whether this inconsistency makes using these classes easier…

It’s certainly not a big issue and it’s probably too late anyways to fix this particular problem. I still wanted to rant a bit… and I’ll take this as an opportunity to search for similar inconsistencies in my own code.


I just noticed: This is my 100th post on this blog! Time to celebrate. Cheers!

Tuesday, February 02, 2010

Implementing a WCF Service in Visual Studio 2008

I’m aware that there are quite a few examples already for how to implement and consume services using WCF in Visual Studio 2008. However, I’d like to provide a slightly different example by providing some additional aspects that you may want to consider for commercial deployments. This includes propagating error conditions and system design aspects, all using the same running example. At times this will certainly stretch the blog format somehow and I may provide a more detailed documentation in a different format.

Enough talk. Let’s get something done!

WCF (Windows Communication Foundation) is a very powerful part of the Microsoft .NET framework. In this post I will show you how to implement a very simple service. And as a running example I’ll use ducks. So the service will be called PondService where ducks can feed. As a tool I’ll use Visual Studio 2008 augmented with ReSharper and AnkhSVN. ReSharper (commercial) is a very powerful tool for refactoring (has some limitation in certain scenarios, e.g. memory consumption) while AnkhSVN (free, open-source) is an extremely helpful plug-in and client for Subversion.

Creating The Solution

As a first step I need an empty solution, which I’ll call RubberDuck. Here’s the recipe:

  1. From the menu select “File” - “New” - “Project…”
  2. In the tree on the left expand “Other Project Types”
  3. Select “Visual Studio Solutions”, then on the right “Blank Solution”
  4. Enter “RubberDuck”

Here is what it should look like:

image

Click “OK”.

Add the Service Library

Next, I’ll add a service library to the solution. We’ll call it DuckServiceLibrary. Here’s the recipe:

  1. In the “Add New Project” dialog in the tree on the left select “Visual C#” then “WCF”.
  2. Then select “WCF Service Library” on the right.
  3. As a name enter “DuckServiceLibrary”.

At this stage the dialog should look as follows:

image

After I click OK the solution looks as follows:

image

Next we’ll add the PondService to the new service library. For this step you need to be aware that there are (at least) two items that look as if they are a fit: “Windows Service” and “WCF Service”. The former would be an old-style web service which technically would work. However, we choose “WCF Service” in the “Add New Item” dialog box. Here is how the dialog looks before I click “Add”:

image

The solution still contains IService1.cs and Service1.cs which were generated when I added the service library. I simply delete them. However, there is more cleanup work required. The DuckServiceLibrary contains a file named “app.config”. Of course I could go in and just delete the entries for Service1. However, there is a second option: The Microsoft Service Configuration Editor. You can launch it from the context menu on “app.config”:

image

There are two places in the Service Configuration Editor (SCE) where I’ll remove the configuration entries for Service1. First there is the Service1 and there is the Service1Behavior:

image Delete the two highlighted nodes. Then make sure you client “Save” before exiting. While I’m comfortable to edit XML files I prefer the SCE since it is harder to accidentally delete items you still need.

The Actual Service Implementation

With all of this in place (just takes a couple of minutes, once you get used to it), I’m now in a position to define the interface I’d like the service to have. To stay with the running example the duck would like to know whether a particular pond is currently frozen or not. During winter a frozen pond doesn’t really help finding food. After removing all unused using’s (ReSharper function) the service interface looks as follows:

    1 using System.ServiceModel;

    2 

    3 namespace DuckServiceLibrary {

    4    [ServiceContract]

    5    public interface IPondService {

    6       [OperationContract]

    7       bool IsFrozen(string pondName);

    8    }

    9 }

The implementation is even simpler. Using the “fake it ‘till you make it” I simply return true. Of course real ducks wouldn’t like that service level so you probably want to offer something more substantial!

    1 namespace DuckServiceLibrary {

    2    public class PondService : IPondService {

    3       #region Implementation of IPondService

    4 

    5       public bool IsFrozen(string pondName) {

    6          return true;

    7       }

    8 

    9       #endregion

   10    }

   11 }

By convention I’ve surrounded the service implementation with a region. In this example it doesn’t make a big difference but once a class becomes larger then it pays off to use a region per interface implementation.

Trying Out the Service

Although I haven’t implemented a client I can still try out what I have so far. Hit F5 and Visual Studio will compile the service library and launch a WcfServiceHost that host the service. It will also launch a WCF Test Client with the PondService added to it already:

image To try the service out I double click on the “IsFrozen()” operation. The WCF Test Client will open a tab in the right hand pane into which I can enter a pond name as follows:

image Next I click the Invoke button and I get the response from the service. I can verify the response in the lower right part of the WCF Test Client window:

image By the looks of it we didn’t make a mistake with our implementation: The Clearwater Lake is frozen.

So this is it for this post. In subsequent posts I’ll cover:

  • How to implement a WCF client?
  • How to exchange data between server and client?
  • How to propagate error conditions?
  • Others

Stay tuned!

Wednesday, January 13, 2010

ASP.NET Web Deployment Projects and Subversion

If you are using both ASP.NET Web Deployment Projects and Subversion you might have come across the issue that the deployment project copies entire folders including the hidden Subversion folders called '.svn'.

To prevent files from being included in the deployment you can modify the project file by modifying the ItemGroup element. Here is an example that excludes '.svn' as well as the C# project file and the intermediate files in 'obj':

<ItemGroup>
   <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\**\.svn\**\*.*" />
   <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\*.csproj.*" />
   <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\obj\**\*.*" />
   <!-- further exclude items here -->
</ItemGroup>

Saturday, January 02, 2010

Compile error in file reference.cs

It's a bit strange but I'm observing the following: ASP.NET Web Application + Service Reference + master page = compile errors in file reference.cs Under certain circumstances the above combination doesn't seem to work in Visual Studio 2008 SP 1. If that is the case you may see compile errors like "The type name 'xxx' does not exist in the type 'yyy' ... Reference.cs ..." For example: To better understand what is going wrong let me also show the project settings: And here is the project layout:The point is that I added a master page named "Dolphin.Master". It has the prefix "Dolphin." which is also the default namespace set for the project. The default namespace in the project settings is used to generate client side code for the service reference. So if you receive a compile error, my recommendation would be to rename the master page to something different than the project's default namespace. When you do, please be aware of the following items as they may lead to follow-on issues:
  1. References to the master page will not be updated in the content pages. You will need to update them manually, e.g. using find-replace.
  2. The same applies for the rename refactoring in ReSharper (version 4.5.1288).
This post applies to Visual Studio 2008 SP1. The system had the latest patch level as of writing. I did not assess whether this issue still exists in Visual Studio 2010 as it hasn't been released yet as a production version. I'd be interested, though, if you find variations of this problem, or if you find different options for resolving it.

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">
</authentication>
<authorization>
  <deny users="?"/>
</authorization>
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:
[Test]
public void MyTextBox() {
   _selenium.Open("http://localhost:49583/");
   _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:
[Test]
public void MyTextBox() {
   _selenium.Open("http://localhost:49583/");
   _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 {
   [TestFixture]
   public class WebSiteTests {
      private string XPathForInput(string identifier) {
         return string.Format("//input[contains(@name, '{0}')]", identifier);
      }

      [Test]
      public void MyTextBox() {
         _selenium.Open("http://localhost:49583/");
         _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("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
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("1.0.0.0")]
// 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.