# Wednesday, January 23, 2008

Over the past few months on the RhinoMocks group I have seen several good ideas for enhancements to the library.  One of the ideas was to add a DoNotExpect.Call helper, which would do the same thing as the LastCall.Repeat.Never() syntax, just in a much more concise way.

This past weekend I added the DoNotExpect.Call() syntax to RhinoMocks, and Ayende has already applied the patch to the RhinoMocks trunk.  Here's how you use the new syntax:

IService svc = mocks.DynamicMock<IService>();

DoNotExpect.Call(svc.Load("Sneal"));

DoNotExpect.Call(delegate { svc.Save("Sneal"); });

 

There are two overloads for the method, one takes an object, and the other a delegate.  For methods that return a value you can use the simpler one without the delegate, however for void methods you need to use the delegate syntax (since something has to be passed in, even if it is technically ignored).

I'm excited about the syntax since I know I will use it quite often on my controller tests that use a lot of dynamically mocked objects.  The syntax I think is also easier to understand, especially for RhinoMocks newbies who have used NMock2 before.

Hopefully I'll have time to add some other enhancements to RhinoMocks in the near future.  It feels good to give back to the software ecosystem every once in a while.

Wednesday, January 23, 2008 6:16:24 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 

I just added another tool to my PC tool belt today thanks to Jeff Atwood.  This got me thinking about all the tools I use for development and just general day to day use of my PC.  Here's a list of one's that I use pretty often.

Development specific tools:

  • Consolas Font Family for Visual Studio 2005/2008 - Makes a nice legible Visual Studio font
  • Fiddler2 - Good for debugging anything over HTTP
  • GhostDoc2 - Quick start my class and method documentation - intelligently.
  • HM NIS Edit - IDE for NSIS installers.
  • IE Developer ToolBar - Firebug light...
  • ReSharper 4 - VS Refactoring tool.
  • MBUnit - xUnit tools for .NET
  • NUnit - xUnit tools for .NET
  • Firebug - Firefox plugin for debugging JavaScript, CSS, and HTML.  Absolutely essential for any web dev.
  • YSlow - Yahoo's web performance analysis tool.
  • WatiN - I use this to drive tests through IE.  Its pretty easy to setup and use.  The newest version supports FireFox!
  • Notepad++ - Opens as fast as Notepad, but has tabs and syntax highlighting.  It comes with a nice installer which adds it to the IE view source context menu.
  • SharpDevelop - Used for editing Boo/Brail.  I think I also used this when I was developing Mono applications on Ubuntu.
  • Subversion - This is what I use for source control at work and at home.
  • Tortoise SVN - Explorer plugin for Subversion.
  • Visual SVN - Non-intrusive Visual Studio plugin for Subversion that just works.
  • Visual Studio 2005 - My C#/C++ IDE.
  • Visual Studio 2005 SP1 - You gotta have web projects.
  • Visual Studio 2005 Extensions for .NET 3 - Use this mainly for WCF.
  • CSAH - Allows you to cut and paste as HTML from Visual Studio.  Essential for blog posts.
  • Syntax Highlighter for WLW - This one works well with every programming language I use.
  • SQL Server 2005 Dev Edition - Primarily the DB I use.
  • SQL Server CE - Sometimes use this for unit tests with NHibernate.
  • MySQL - Started using this recently, the installer for Windows makes it dumb easy to setup.
  • Java SDK 1.6 - uh yeah.
  • Eclipse - Sometimes need this for Java (and C++ programming on Linux).
  • ActivePerl - Our C++ xUnit test framework requires this.  There's a free version if you click the right link.
  • CxxTest -C++ xUnit test framework.
  • RhinoMocks - Fluent mock object framework for .NET.
  • PowerShell - A powerful Windows command shell.
  • CruiseControl.NET (CCTray) - Keep the team in touch with the build.
  • WinMerge - Nice merge/diff tool especially considering that its free like beer.
  • TestDriven.NET - Since I'm now force to use MSTest, this an essential tool to keep the TDD rythm.
  • FxCop - Nice to run every once in a while... to catch stuff, especially related to globalization.

Non-Development specific tools:

  • Virtual PC 2007 - Use this run virtual PCs, generally for integration testing.
  • Miranda IM - I get tired of having multiple IM clients, this allows me to use them all at once (and it's OSS).
  • Pidgin - Multi-function IM client which just works.  Much better than Miranda.
  • Firefox3 - My preferred browser, which runs JavaScript heavy sites fast.
  • 7-Zip - An awesome zip/tar/rar/whatever utility.
  • FoxIt PDF Reader - A light and fast version of Adobe Reader that doesn't constantly nag me about updates.
  • ClipX - My newest install, this one allows you to maintain a clipboard history.  I'm loving this one.
  • DisplayFusion - I generally just use this to drag maximized windows between monitors.
  • Windows Live Writer - What I write this blog on.
  • Paint.NET - A powerful .NET paint and photo editor package.  I've dumped my old copy of Photoshop 7 for this.
  • Launchy - Since I'm stuck on XP, this makes finding and starting programs uber quick.

The one overriding theme of all these packages is that most of them are free and/or OSS.  Pretty cool.

Wednesday, January 23, 2008 2:17:41 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
# Tuesday, January 22, 2008

While looking for information on multi-threaded debugging for Visual Studio 2005, I found this article by Peter Bromberg that has some decent Visual Studio 2005 debugger tips.  Its definitely worth reading over if you use Visual Studio 2005.  I know I learned a thing or two.

One tip I would add to this article is to use the immediate window when debugging.  It seems like all VB'ers know about this one, but relatively few C# developers do. 

The immediate window allows you to evaluate code while debugging.  Lets say I wanted to print out the value of a property in the immediate window, I could do any these expressions:

ImmediateWindow

I find this is often faster than trying to dig through a watch window, especially on a large class.

You can even call code directly from the immediate window, which I think is where it's real power lies.  With this you can create a generic debug method in your code that prints out all the values of a collection, which can then be called from the immediate window passing in any collection.

internal static void PrintAll(IEnumerable coll)
{
    foreach (object item in coll)
        Debug.Print(item.ToString());
}
Tuesday, January 22, 2008 5:17:53 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Sunday, January 20, 2008

I needed to get directions to a friends house today and sure enough I found myself using Google Maps to get directions.  Nothing astounding about that.  What did astonish, and delight me, was the fact that I found you can change your route just my dragging and dropping the route line displayed on the map!  Is this thing really a web application running on just HTML and JavaScript?

Even more amazing is that you can create hyperlink to send out to people using your new preferred route just by clicking "Link to this page."  I assumed it would lose my customized route, but it doesn't, it keeps it in the URL by specifying a direction change at an intersection.

From now on when sending directions or even my address I'm going to make sure to send it as a hyperlink to Google Maps.  It just makes sense.

Sunday, January 20, 2008 7:21:33 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, January 17, 2008

Setting up Monorail to work on IIS7 isn't necessarily straight forward.  First you need to configure IIS7 to handle the particular file extension you are using for Monorail.  This is just like you would do in IIS6, but with some slightly different menus and terminology.

I'm using .rails for this particular application.  For the website or virtual directory you are configuring in IIS7, open the Handler Mappings in IIS Manager.

HandlerMappings

From there create a new Script Map, by clicking "Add Script Map..."  This opens the Script Map dialog.  You should enter *.rails as the request path and the aspnet_isapi.dll path as the executable.

EditScriptMap

Once that is done, click "Request Restrictions" and then uncheck "Invoke Handler only if request is mapped to".

RequestRestrictions

Once that is done you may run into a problem with your monorail section in the web.config.  I had this error:

An error occurred creating the configuration section handler for monoRail: Object reference not set to an instance of an object.

 

Odd, my web.config works in IIS6 and in webdev.webserver.exe.  As it turned out I had to fill out the assembly element in my MonoRail section even though I'm using Windsor integration.  I've bolded the part I had to add below:

 

<monorail useWindsorIntegration="true">
  <controllers>
    <assembly>Sneal.Store.Commerce</assembly>
  </controllers>
  <viewEngines viewPathRoot="Views">
    <add type="Castle.MonoRail.Framework.Views.NVelocity.NVelocityViewEngine, Castle.MonoRail.Framework.Views.NVelocity" />
  </viewEngines>
</monorail>
Thursday, January 17, 2008 3:44:58 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 

We all know that since Internet Explorer is integrated into the OS that you can't have two different versions of IE on one PC.  I have Vista on all my PCs, and there's no way to run IE6 on Vista.  What is a developer to do?  We could create Virtual PC running Windows XP with IE6, but why bother when the IE team has already created a freely downloadable IE6 Virtual PC image for you?  This is a lot easier and faster then going through the Windows setup wizard.

They have an IE7 image too.

Thursday, January 17, 2008 2:31:02 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, January 14, 2008

The footer now appears at the bottom of the blog in IE (IE 7 anyway).

The content area is floating so that the blog now takes full advantage of your wide screen monitor.  It certainly makes this blog a lot easier to read in 1600x1050.

Monday, January 14, 2008 7:45:02 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

I posted last week about testing JavaScript through NUnit with JSUnit.  While this worked, it was a little slower to run tests than I really wanted.  It was also slower (for me) to write the tests since I had to leave the comfort of NUnit and .NET for JSUnit and JavaScript.

I'm continuing to look at the problem of JS testing for ASP.NET.  I evaluated YUI Test, Yahoo's JS unit test library.   YUI Test actually looks very good, but I really wanted to keep things integrated with my current build and test process, even if it isn't the best solution; you don't know unless you try.  ;-)

This time I'm only using NUnit and WatiN for my JavaScript tests.  Since WatiN now has the ability to evaluate JavaScript and return the results, I'm using this to run the JavaScript function under test and then using an NUnit assertion for validation.

I create each test using regular NUnit syntax, and then wrap the JavaScript function call with a C# method which passes the arguments off to the JS function to test.

[Test]
public void ShouldValidateDiscover()
{
    Assert.IsTrue(ValidateCreditCard("6011648040903965", "discover"));
}
 
private bool ValidateCreditCard(string cc, string ccType)
{
    string testJs = string.Format("var cc = new CreditCardValidator(); cc.isValidCreditCardNumber('{0}', '{1}');", cc, ccType);
    return EvalToBool(testJs);
}

The EvalToBool method just calls the WatiN eval method which accepts JavaScript as a parameter, and then converts the JS string result to a .NET boolean.

protected bool EvalToBool(string js)
{
    string result = ie.Eval(js);
    return bool.Parse(result);
}

The overall process is:

  1. Create a dummy HTML page which includes the JavaScript source file I want to test.
  2. Kick off WatiN and navigate to the dynamically created HTML file.
  3. Pass the JavaScript function to be evaluated by WatiN.
  4. Assert the eval call results using NUnit.

The test setup is very simple, and it runs fast for this type of test.  On my PC it was taking 1.7 seconds to setup the test fixture, and then .2 seconds to run each test.  The nice thing is that the errors are generally obvious and easy to diagnose since they are native NUnit tests.  Its also nice to have multiple NUnit test entries in the runner instead of one monolithic JavaScript test function which encapsulated all my JS tests that run in JSUnit. 

The tests can get ugly if a JavaScript exception is thrown, in that case you get a generic COM exception returned from WatiN rather than a nice error message.  The is one area where a JSUnit or YUI test are naturally better at.

This makes me wonder if WatiN couldn't be extended to return better error information from JavaScript, and whether the use of a dynamic .NET language along with NUnit couldn't make for a nice testing experience.

Monday, January 14, 2008 6:44:21 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Sunday, January 13, 2008

I created a new utility called ConfigPoke for creating application configuration files from a template and one or more property files.  The property files allow you to create a set of property files in which each subsequent file overrides any settings in the previous.

The input property files are just plain text files with key value pairs, for example:

dbConnectionString        = server=localhost;database=Northwind;integrated security=SSPI
sessionConnectionString = server=localhost;database=AspState;integrated security=SSPI
smtpServer                  = localhost

 

This allow me to define a base set of shared developer properties and then I can define my own property file for me which overrides just properties, like the local database connection string.  I also define property files for each of my environments I deploy the application too: dev, test, release, live.

This utility integrates tightly with MSBuild and Visual Studio 2005/2008 using it's own target file.  There is also a command line interface for the application that can be used from NAnt or in your deployment process (NSIS in my case).

Per developer configuration happens automatically and is always up to date with the input template and property files with Visual Studio integration.  The output configuration files are conditionally built only if the input templates file or input property(s) files are changed, just like any regular source file in Visual Studio. If a Rebuild action is initiated in Visual Studio, the output configuration files are always rebuilt, even if the input files have not changed.

 

I've been using this utility for the past week at work, and it has worked really well.  Edit a property and everything just works.  Machine specific settings have proven invaluable especially on my laptop which has a lot of non-standard settings because I usually work disconnected on it.

 

You can download the MSBuild target DLL, console EXE, and MSBuild targets file from Google Code.  The code and the binary is release under the Apache 2.0 license.

Visual Studio 2005/2008 Integration Outline

  1. Import Sneal.Build.ConfigPoke.targets file into your VS project file.
  2. Create a ConfigTemplateFiles ItemGroup.
  3. Create a ConfigPropertyFiles ItemGroup.

Detailed Visual Studio 2005/2008 Integration Instructions

Include the Sneal.Build.ConfigPoke.targets file in your Visual Studio project file (csproj) using the following element:

<Import Project="Sneal.Build.ConfigPoke.targets" />

With the ConfigPoke MSBuild targets file included, the configuration building will automatically be hooked into the Visual Studio clean, build, rebuild process.

The Sneal.Build.ConfigPoke.targets file requires two MSBuild item groups as input: ConfigTemplateFiles?, and ConfigPropertyFiles?. These must be specified in your MSBuild (csproj) project file. Each ConfigTemplateFiles? item should be the destination filename + some arbitrary extension, I use '.template'. You may also probably want to set the "InProject?" item meta data to false so these templates or property files don't show up in VS solution explorer.

Here's an example ConfigTemplateFiles? ItemGroup? that you would put into your csproj file:

<ItemGroup>
  <ConfigTemplateFiles Include="$(MSBuildProjectDirectory)\Configs\web.config.template"/>
  <ConfigTemplateFiles Include="$(MSBuildProjectDirectory)\Configs\windsor.config.template" />
</ItemGroup>

To create user and machine specific overrides, you can include a base properties file and then optionally include a per user and per machine config, if they exist. This would allow each developer to create their own override properties file which can then be optionally checked into source control. To automatically set this up, you can take advantage of the built in MSBuild properties: USERNAME and COMPUTERNAME.

Here's an example ConfigPropertyFiles? ItemGroup? that you would put into your csproj file:

<ItemGroup>
  <ConfigPropertyFiles Include="$(MSBuildProjectDirectory)\Properties\App.Properties.base"/>
  <ConfigPropertyFiles Include="$(MSBuildProjectDirectory)\Properties\App.Properties.$(USERNAME)" Condition="Exists('$(MSBuildProjectDirectory)\Properties\App.Properties.$(USERNAME)')"/>
  <ConfigPropertyFiles Include="$(MSBuildProjectDirectory)\Properties\App.Properties.$(COMPUTERNAME)" Condition="Exists('$(MSBuildProjectDirectory)\Properties\App.Properties.$(COMPUTERNAME)')"/> 
</ItemGroup>

Note: You cannot pass in non-existant property files to the ConfigPoke utility, hence the Condition check above.

 

Optionally you can specify a ConfigPokeDirectory? and a ConfigOutputDirectory? property to override the default directories. The ConfigPokeDirectory? property should point to the directory where Sneal.Build.ConfigPoke.MSBuild.dll is located on your machine, if not specified this property will default to the current MSBuild project file directory. The ConfigOutputDirectory? property should point to the directory where the output configuration files are written too. If not specified this property will default to the current MSBuild project file directory.

 

For additional usage see the example in SVN, http://sneal.googlecode.com/svn/trunk/ConfigPoke/Sneal.Build.ConfigPoke.Example/Sneal.Build.ConfigPoke.Example.csproj

Sunday, January 13, 2008 1:39:35 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, January 12, 2008

I like to re-use code between projects, whether for personal use or professionally, so I created an Apache 2.0 licensed code repository.  Right now I just have my application configuration build tools committed (which I'll post about later).

The project home page is: http://code.google.com/p/sneal/

The project SVN URL is: http://sneal.googlecode.com/svn/trunk/

Saturday, January 12, 2008 8:01:44 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, January 10, 2008

The company I work for, GalleryPlayer in downtown Seattle (Pioneer square), is looking for a couple of software engineers to develop our next generation content distribution system.  I've worked for GP since last May and I really enjoy the work and the people

Why would anyone want to work for our small startup?

  • As an engineer you'll have a lot of influence over technology and design.
  • We prescribe to the Programmer Bill or Rights.  No you won't have your own office.
  • Our dev environment consists of: SVN, CC.NET, VS 2005, Re#, SQL Server 2000, NUnit.
  • Good location, Pioneer Square in downtown Seattle.  5 minute walk from the Sounder commuter rail station and bus lines.
  • Casual work environment - wear whatever makes you comfortable.
  • All the free, fresh, Starbuck's you can drink... and a toaster.  Yes, we trust you with a toaster!
  • We're using Castle Windsor, MonoRail, and Prototype for our web development backed by unit tests (and perhaps ASP.NET MVC when MS releases a Go Live license).
Thursday, January 10, 2008 9:03:38 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

I consolidated a few duplicate categories and removed some others that just had one post under them to make the site a little more usable.  Next I'm going to work on the look and feel of this blog and make it work better in IE.

Thursday, January 10, 2008 8:30:23 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

Developed data access class containing over 5,000 lines of code and over 100 methods

WTF
Thursday, January 10, 2008 8:28:45 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, January 09, 2008

We've all written a few console apps in our time, but how often do we spend anytime creating a help command line switch that spits out how to use the app?  Hopefully you answered, "everytime."  There's nothing more annoying than a console app that doesn't display a man page if you forget to supply required parameters.

It's so easy to add syntax help, especially if you drop the Console.WriteLines in favor of an embedded text file resource.  This way you can edit your command line usage as plain text which is so much easier to write and maintain.  This may seem obvious, but often time we forget because, "it's just a quickie console app."  So the next time your find yourself writing a console utility, remember to use an embedded text resource as your help (or man) page.

EmbeddedResource

Other than actually creating the text file and marking it as an embedded resource, this all the code required (don't forget to prefix your text file with the default assembly namespace):

private static void Usage()
{
    using (
        Stream s =
            Assembly.GetExecutingAssembly().GetManifestResourceStream(
                "Sneal.Build.ConfigPoke.Console.usage.txt"))
    {
        using (StreamReader reader = new StreamReader(s))
        {
            System.Console.WriteLine(reader.ReadToEnd());
        }
    }
}
Wednesday, January 09, 2008 6:51:36 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, January 07, 2008

I have no proof of this other than my changes weren't showing up, but it seems like MSBuild project files that are directly imported into a project are cached in Visual Studio between builds.  I had to make changes to my imported build script, exit Visual Studio, then restart VS before my changes would take affect.  Luckily if you build from the command line this doesn't happen.

Monday, January 07, 2008 8:45:28 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

I often need to refer to tools and libraries in my SVN repository that live in a folder not underneath the current project folder.  For instance I may need to use NUnit from trunk\store\web, but NUnit lives under trunk\tools\nunit\bin. 

Relative to the trunk, I know where to find NUnit, but where's the trunk?  The trunk may be checked out to c:\source\mytrunk or e:\work, or even the user's documents and settings folder.  This means I must use relative paths to NUnit from the current project directory, but this gets tricky if I have an external MSBuild target file that is shared between projects.

The only way to tell the shared imported targets file where things are relative to it, is to have the parent MSBuild script to pass in a property telling it where the root of the source control folder is (or where the tools directory is).  In my case this is the 'SourceDirectory' property which should point to the root of my source control folder hierarchy.  This gets annoying after a while since everywhere I include the shared targets file I first must create the SourceDirectory property first, like so:

<PropertyGroup>
  <SourceDirectory>$(MSBuildProjectDirectory)\..\..</SourceDirectory>
</PropertyGroup>

 

Yes this works pretty well, but it makes the shared imported targets file not-so-self contained and I have to repeat this over and over again in every project file that wants to include the shared targets files, which in my case is every single csproj file.  I have to do this since my project files live at varying depths in the folder hierarchy.  Instead of specifying this property everywhere, I've put this at the top of my shared targets file:

<PropertyGroup Condition="'$(SourceDirectory)' == ''">
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\Master.proj')">$(MSBuildProjectDirectory)</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\Master.proj')">$(MSBuildProjectDirectory)\..</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\..\Master.proj')">$(MSBuildProjectDirectory)\..\..</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\..\..\Master.proj')">$(MSBuildProjectDirectory)\..\..\..</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\..\..\..\Master.proj')">$(MSBuildProjectDirectory)\..\..\..\..</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\..\..\..\..\Master.proj')">$(MSBuildProjectDirectory)\..\..\..\..\..</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\..\..\..\..\..\Master.proj')">$(MSBuildProjectDirectory)\..\..\..\..\..\..</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\..\..\..\..\..\..\Master.proj')">$(MSBuildProjectDirectory)\..\..\..\..\..\..\..</SourceDirectory>
  <SourceDirectory Condition="'$(SourceDirectory)' == '' And Exists('$(MSBuildProjectDirectory)\..\..\..\..\..\..\..\..\Master.proj')">$(MSBuildProjectDirectory)\..\..\..\..\..\..\..\..</SourceDirectory>
</PropertyGroup>

 

What this does is look for a Master.proj file in each directory traversing upwards until it finds one, at which point the SourceDirectory property becomes set.  I can do this since I know that I only ever have one Master.proj file in the root of my SVN repository, and I never have a project more than 4 folders deep (although here I support 9 levels)  It's kind of cheesy, but it works well and saves me from having to do anything other than just import the shared targets file.

<Import Project="$(MSBuildProjectDirectory)\..\..\utils\gp.vs.targets" />

 

Hopefully Microsoft will add a well known property that allows you to get the current directory of the current build file, rather than just the parent script directory like MSBuildProjectDirectory does now.

Monday, January 07, 2008 7:46:42 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, January 05, 2008

Environment specific configuration can be a real pain to manage effectively.  I think I've tried every approach imaginable and it seems there is no perfect solution.  I just switched my many environment specific configuration files (I actually got to delete ~25 config files from SVN!) over to a handful of Windsor configuration files that use conditional elements and includes like so:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <properties>
    <?if LIVE?>
      <billingGatewayHost>webserver1</billingGatewayHost>
      <sessionConnectionString>server=dbserver1;database=ASPStateNET2;integrated security=SSPI</sessionConnectionString>
    <?elseif TEST?>
      <billingGatewayHost>webserver3</billingGatewayHost>
      <sessionConnectionString>server=dbserver3;database=ASPStateNET2;integrated security=SSPI</sessionConnectionString>
    <?end?>
  </properties>
</configuration>

 

I had so many configuration files because I had 5 environments, plus a session state, http module, appSettings, and some other stuff broken out into separate files using the standard .NET include section file mechanism.

I think I like the conditionals better than separate files for each environment which requires a postbuild process either at build or deployment time to merge or copy XML.  Also, it should be pretty obvious to any developer what's going on here.  Unfortunately the standard ASP.NET configuration mechanism doesn't have anything like this, and what's worse is that some components - like session state as in my case - can only be configured through the web.config.

That means no overriding the configuration at runtime or using Windsor.  No, the internal SqlSessionStateStore class in the FCL reads directly from the web.config using an internal static helper class.  This means no inheritance or injecting my configuration, even with the help of reflection.

ASP.NET does support custom session state providers, however I just want to use the SqlSessionStateStore class with a different configuration mechanism (I would really like to wire the thing up using Windsor); and creating a brand new provider is a lot of work.

Since all of my properties (i.e. connection strings) are in an external Windsor configuration file, it makes the most sense to also put my conditional session state connection strings in there as well (if you haven't picked up on it yet, I'm using SQL Server to store my session data, hence the SQL connection string for session).

Here's how I ended up getting the SqlSessionStateStore to use the connection string from my Windsor config...  And here is the hack in the global.asax.cs... 

private static volatile bool appDomainIsShuttingDown = false;
 
public override void Application_Start(Object sender, EventArgs e)
{
    base.Application_Start(sender, e);
 
    if (IoC.Resolve<SessionStateConnectionStringSetter>().SyncWebConfigSettingIfDifferent())
    {
        HttpRuntime.UnloadAppDomain();
        appDomainIsShuttingDown = true;
    }
}

 

On application start my base Application_Start method gets my DI container up and running.  After that I ask the container for a SessionStateConnectionStringSetter instance which is injected with the proper session DB connection string from the container.  All this class does is modify the web.config if the connection string it has differs from the one in the web.config.  After that, if the web.config has been modified, the current app domain is shutdown and the appDomainIsShuttingDown flag is set to true. 

In case you're not sure, static variables are scoped to the current app domain by default, so the next request for the web app will have the appDomainIsShuttingDown variable set to false (it's default value).  I think there is a threading bug in there if multiple application start events get fired off simultaneously, so I should probably add a lock around the web.config update.  I'll have to look into that.  Anyway, here's the class that updates the web.config with the new session state connection string.

public class SessionStateConnectionStringSetter
{
    private readonly string sessionStateConnStr;
 
    public SessionStateConnectionStringSetter(string sessionConnectionString)
    {
        this.sessionStateConnStr = sessionConnectionString;
    }
 
    public bool SyncWebConfigSettingIfDifferent()
    {
        ExeConfigurationFileMap map = new ExeConfigurationFileMap();
        map.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config");
 
        Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
        SessionStateSection session = (SessionStateSection)config.GetSection("system.web/sessionState");
 
        if (session.SqlConnectionString != sessionStateConnStr)
        {
            session.SqlConnectionString = sessionStateConnStr;
            config.Save();
            return true;
        }
 
        return false;
    }
}

 

Further along in the ASP.NET pipeline the Application_BeginRequest method executes and the current user request (the one that initiated the web.config to be updated in the first place) is redirected - back to the same page they asked for originally.  This is done so the user doesn't see a nasty exception that will likely happen if processing continues with the original incorrect session DB connection string.

protected void Application_BeginRequest(object sender, EventArgs e)
{
    // This will cause the user to re-request the page using a new appdomain
    if (appDomainIsShuttingDown)
        Response.Redirect(Request.Url.ToString());
}

 

The thing to note about all this, is that the web.config update should only ever happen on the very first request for the application after a deployment, which not too surprisingly will almost always be the person doing the deployment (assuming they check their work). 

I wish I could find a better way to do this, but as far as I can tell there's no other way to set this programmatically at runtime.  I may just break down and add a special case to my NSIS installer to update the web.config session connection string from my Windsor configuration.  I really just wanted to see if I could get this to work without a build or deploy step...

Saturday, January 05, 2008 9:25:15 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, January 04, 2008

For 15 minutes today I couldn't figure out why my Windsor configuration was blowing up with a mysterious and unrevealing error: "deserialize element cannot process element component."  This happened after I moved some configuration out of my main windor config to a new embedded resource config file. I thought is this a bug in Windsor?  After briefly looking through the Windsor test source it was pretty obvious that this is supported and tested.

It turns out that I forgot to include the "components" tag in my config file.  Argh!  The answer was right in front of me all this time, I just didn't see it - even after comparing my broken config to a working config.  I'm glad I'm not the only one to have this problem...

Friday, January 04, 2008 7:01:38 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  | 
# Thursday, January 03, 2008

For Christmas my wife got me a new Zune 8GB, which I'm really enjoying so far.  I think Microsoft has done a really good job putting the newer Zune's together.  Not only is the UI pleasant, but the thing light weight and easy to use, which is in sharp contrast to the older hard drive based devices.  Originally my wife got me a 16GB SanDisk Sansa View, which would constantly freeze up, even after a firmware Flash.  I just wanted something that works, so I got a Zune.

Now that I can listen to podcasts on the commute to and from work, I've done a little bit of searching and thought I would try out the following podcasts:

  • DotNetRocks
  • Hanselminutes
  • Polymorphic Podcast
  • FLOSS Weekly
  • Agile Toolkit Podcast

I got these from these Ayende and Jeffrey Palermo's blog posts and comments.

As a side note I stumbled upon what Ayende Rahein means: Freedom Dawn.

Thursday, January 03, 2008 11:07:40 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

I needed to make a change to some existing legacy* JavaScript that validates credit card numbers in the browser.  For the most part the project was green field except for a few services, so overall test coverage was very good - except for the JavaScript code.  The lack of test coverage in the increasingly growing JavaScript libraries was starting to really bother me, so I set out to find a way to create "unit" tests for my JavaScript code that didn't require any setup or any extra steps for another developer to run.  What I really was wanting, was for my JS tests to be integrated and run along side my NUnit tests.

After some searching it appeared that JsUnit looked to be the most widely used and supported JavaScript testing facility available.  The one problem with this is that it requires you run the tests through a frame in a browser, which is a whole lot slower and less integrated with our NUnit tests that I wanted.

To get faster feedback on my JS tests I immediately thought of using WatiN to drive the JsUnit tests.  After a quick Google search I found that Adam Esterline had already done something very similar.  The main difference between what he's done and what I wanted was that I wanted JsUnit errors results right there in my ReSharper test runner window and I wanted my test scripts to be pure JavaScript rather than HTML files that JsUnit uses (because I wanted to keep the SOC high, and be able to dynamically change the location of JsUnit relative to my test scripts).  Like Adam, I'm auto generating a test HTML page for JsUnit and using WatiN to drive IE (although since I get my results outside of IE, I'm thinking I can drop using WatiN altogether for this and make it browser independent).

The workflow for using the JsUnit utility library is as follows:

  1. In your test project include a reference to JsUnit.Utils.dll
  2. Create a folder (or two) to contain your JavaScript JsUnit test fixtures.
  3. Create your JsUnit test fixtures as separate .js files.
  4. Create a .NET NUnit test fixture with a test that runs the JsUnitTestRunner from JsUnit.Utils.

Here's my solution explorer window with the JsUnit.Utils reference and the c# and the JavaScript fixtures.

JsUnitSlnExplorer

Once that is setup you create a single NUnit test that kicks off all the JsUnit tests.

/// <summary>
/// This runs all JsUnit tests found in the JavaScript folder and makes
/// their results available through NUnit (if any fail).
/// </summary>
[TestFixture]
public class JavaScriptFixture
{
    #region Setup/Teardown
 
    [SetUp]
    public void SetUp()
    {
        jScriptTestDir = AppDomain.CurrentDomain.BaseDirectory + "\\..\\..\\JavaScript\\";
        jsUnitDir = ConfigurationManager.AppSettings["JsUnitDir"];
    }
 
    #endregion
 
    private string jScriptTestDir;
    private string jsUnitDir;
 
    [Test]
    public void RunAllJSUnitTests()
    {
        Assert.IsTrue(Directory.Exists(jScriptTestDir),
                      string.Format("Could not find the JsUnit tests directory: '{0}'", jScriptTestDir));
 
        Assert.IsTrue(Directory.Exists(jsUnitDir),
                      string.Format("Could not find the JsUnit directory: '{0}'", jsUnitDir));
 
        ITestFileReader reader = new SuffixTestFileReader(".js", new TestFileReader(jScriptTestDir));
        new JsUnitTestRunner(reader, jsUnitDir).Run();
    }
}

 

Running this test through the ReSharper Test Runner runs all my JsUnit tests, so when I choose "Run All Tests from Solution," it really means "run all tests".  More importantly, if any JsUnit tests fail during execution the JsUnit error is displayed in the output window.  Here's my "testShouldValidateCreditCard" test that is failing which shows the JsUnit error text:

JsUnitInsideNunit

If you've ever used JsUnit before I bet you're wonder how I'm getting the result back, since JsUnit is entirely web based and only supports posting results to a URL (generally for use with the JsUnitServer).  What I'm doing is unpacking an ashx file that is an embedded resource, copying the current running DLL (JsUnit.Utils.dll) to the bin directory under the current running directory, and then starting the .NET 2 webserver.webdev.exe to listen for results using the unpacked ashx file.  The results are then saved out to a predetermined text file which JsUnitTestRunner is looking for and then parses out any errors.  I could use .NET remoting or something fancier, but this works well enough for now.

There's still a lot that could be done to clean this up, like removing the WatiN dependency, adding new features and so on.  There are also a few bugs I need to work out, but so far so good.

*legacy in the sense that there were no unit tests, even though the code is only a month old.

Thursday, January 03, 2008 12:00:20 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  |