This blog has moved, permanently, to http://software.safish.com.

Tuesday, August 31, 2010

Using the WiX Installer

I’ve been playing with the Wix Installer for the last few days, and I’m absolutely amazed by it.  It’s a real bastard to get into, but once you’re up and running it’s pretty incredible how much can be customised.  There is a LOT of documentation out there, but the most useful link I found was this tutorial – it really is worth your while to read the entire tutorial BEFORE trying to create your own installation project.

Instead of creating another tutorial, I thought I’d list the items that tripped me up.

Visual Studio 2010 Integration

I downloaded Wix 3.0 (64 bit), and after installation, it wasn’t available as a project within Visual Studio.  Download the beta version of 3.5 – it seems pretty stable and integrates with Visual Studio,.

No Wizard

No wizard!?  WTF!?  It turns out it’s XML-based – you end up doing a lot of the setup by hand.  Deal with it.

References in Visual Studio

You will probably require extensions so you can customise the UI, or perhaps ensure the user has a .NET Framework installed.  I’m working in Visual Studio 2010, and I wasn’t sure how to do this so I added compiler and linker options in the project properties.  You do not need to do this.  All you need to do is click “Add Reference” on the project, and select the extension from the list that appears.  For example, if you want to add the .NET Framework prerequisites, right-click References, and select WixNetFxExtension.  That is all you need to do.

Default UI

The default installation dialog really sucked, and it took me a while to work out that you need to specify a different UI type.  That’s what you get for not reading the above tutorial before creating your project.  You need to create a <UI> element, and specify the UIRef you want to use.

Dialog Sequence

Creating custom dialogs is pretty easy once you get the hang of it, but I struggled a little with navigation between dialogs.  Eventually I found the reference on the Wix site to a full list of Wix dialogs that you can navigate between at http://wix.sourceforge.net/manual-wix3/WixUI_dialogs.htm.

Using the IIS Extension (For deploying web sites)

This foxed me a little too.  Mostly, using the extensions just worked in Visual Studio, but the IIS extension doesn’t.  You need to add the namespace reference, something along the lines of:

<wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension" xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">

You can then use the extension elements as follows:

<iis:WebSite Id='DefaultWebSite' Description='Default Web Site'>
       <iis:WebAddress Id='AllUnassigned' Port='80' />
     </iis:WebSite>

Thursday, August 26, 2010

Unit Testing and DateTime Comparisons

 

One thing I’ve found annoying for the long time, is trying to assert DateTime equality when unit testing, particularly when the DateTimes have been parsed from strings in the underlying method.  Two DateTime constructs, despite being identical in terms of their values, often won’t assert as being equal and your unit test fails.  As such, you end up doing other sorts of tests, for example checking the individual values.

To help test dates, what I’ve done is created a helper class for asserting two dates are “equal”, to a specifed level of precision:

public static class AssertHelper
    {
        /// 
        /// Asserts that two dates are equal by checking the year, month, day, 
        /// hour, minute, second and millisecond components.
        /// 
        /// The current date
        /// 
        public static void AreDatesEqual(DateTime expected, DateTime actual, DateTimePrecision precision)
        {
            if (precision >= DateTimePrecision.Year && expected.Year != actual.Year)
            {
                throw new NUnit.Framework.AssertionException("Year in dates do not match as expected.");
            }
            if (precision >= DateTimePrecision.Month && expected.Month != actual.Month)
            {
                throw new NUnit.Framework.AssertionException("Month in dates do not match as expected.");
            }
            if (precision >= DateTimePrecision.Day && expected.Day != actual.Day)
            {
                throw new NUnit.Framework.AssertionException("Day in dates do not match as expected.");
            }
            if (precision >= DateTimePrecision.Hour && expected.Hour != actual.Hour)
            {
                throw new NUnit.Framework.AssertionException("Hour in dates do not match as expected.");
            }
            if (precision >= DateTimePrecision.Minute && expected.Minute != actual.Minute)
            {
                throw new NUnit.Framework.AssertionException("Minute in dates do not match as expected.");
            }
            if (precision >= DateTimePrecision.Second && expected.Second != actual.Second)
            {
                throw new NUnit.Framework.AssertionException("Second in dates do not match as expected.");
            }
            if (precision >= DateTimePrecision.Millisecond && expected.Millisecond != actual.Millisecond)
            {
                throw new NUnit.Framework.AssertionException("Millisecond in dates do not match as expected.");
            }


        }
    }

    public enum DateTimePrecision
    {
        Year = 0,
        Month = 1,
        Week = 2,
        Day = 3,
        Hour = 4,
        Minute = 5,
        Second = 6,
        Millisecond = 7
    }
This effectively allows me to unit test that the dates were close enough, without worrying to much about the exact equality. This solution, although working, somehow feels dirty. I'd love to know if anyone else has any better solutions for unit testing date equality in .NET.

Tuesday, August 3, 2010

ILMerge

I Used ILMerge today for the first time, and it's great. Aspnet_merge.exe is actually based on this tool, and it allows you to combine all your assemblies into a single exe or dll - great for simple deployment.

It gets installed by default to C:\Program Files (x86)\Microsoft\ILMerge, with fairly decent documentation. To consolidate a fairly simple Windows exe with three dlls into a single exe, all I did was the following:

ILMerge.exe /t:winexe /out:Output.exe /ndebug Program.exe Lib1.dll Lib2.dll Lib3.dll