• Programmatically setting a connectionString property

    The application we are developing will be installed at different locations and consequently will need to connect to a local SQL Server instance.

    Rather than build separate configurations and installers for every site, we’re planning to store this information centrally. The application then uses a web service to retrieve the appropriate configuration information for its site.

    As we are using NHibernate/ActiveRecord with the database configuration being loaded though the Castle ActiveRecord Integration Facility, the database name is indicated through naming a connection string (by specifying the config key ‘hibernate.connection.connection_string_name’). The difficulty is that this appears to be loaded the first time Windsor loads the config file. What we need is a way of replacing the connection string that was read from the app.config file with one that we’ve retrieved from the web service.

    The main problem that needed to be overcome is that .NET doesn’t allow you to change the connection strings after they are read from the app.config file. If you try to do it, it will throw a ConfigurationErrorsException with the message “The configuration is read only”. The following code illustrates this:

    var settings = ConfigurationManager.ConnectionStrings[0];

    settings.ConnectionString = “blah”;

    Steve Michelotti describes how you can override ConnectionStringsSection’s IsReadOnly method, which would be fine for custom configuration sections but doesn’t work in this case as the class is sealed.

    Dmitry suggests another approach, though at the time it was just an untested idea. ConnectionStringSection inherits from the abstract class ConfigurationElement. Using Reflector you can see that the default implementation of IsReadOnly just returns the value of a private field _bReadOnly, which is set to true.

    We use reflection to locate the private field _bReadOnly and then force it to be false. eg.

    var settings = ConfigurationManager.ConnectionStrings[ 0 ];

    var fi = typeof( ConfigurationElement ).GetField( “_bReadOnly”, BindingFlags.Instance BindingFlags.NonPublic );

    fi.SetValue(settings, false);

    settings.ConnectionString = “Data Source=Something”;

    This is a bit of a hack and obviously would fail should Microsoft choose to change the name of this private field in the future, but as long as we do this before the container loads the configuration, it means that in the example above, any reference to the first connection string will return our new value.

    An alternate approach might be to implement a custom NHibernate configuration provider, but I’ll leave that exercise to the reader :-)

  • Running WiX on Windows Server 2008

    Our CruiseControl.NET build server is running Windows 2008. Today I added a WiX project to generate an MSI for one of the projects. This ran fine on my local machine.

    I followed the instructions from the WiX 3.0 help file on “Integrating WiX Projects Into Daily Builds” with one exception - Step 2 adds a new section to the .wixproj file, but I had to remove the $(WixToolPath) prefix from the WixTasksPath element. eg.

    <PropertyGroup>

    <WixToolPath\>..\\Tools\\Wix\\</WixToolPath\>
    
    <WixTargetsPath\>$(WixToolPath)Wix.targets</WixTargetsPath\>
    
    <WixTasksPath\>wixtasks.dll</WixTasksPath\>
    

    </PropertyGroup>

    I then checked this in and watched the build die with the following error:

    light.exe (,): errorLGHT0217: Error executing ICE action ‘ICE01’. The most common cause of this kind of ICE failure is an incorrectly registered scripting engine. See http://wix.sourceforge.net/faq.html#Error217 for details and how to solve this problem. The following string format was not expected by the external UI message logger: “The Windows Installer Service could not be accessed. This can occur if the Windows Installer is not correctly installed. Contact your support personnel for assistance.”.

    Others have had similar problems, and the solution seems to be to make sure that the account the build process runs as is a member of the local Administrators group.

  • Deleting the “Program Files” directory

    No, don’t worry I’m not that crazy. On the HTPC, I initially installed Vista on the 1Tb disk. When the replacement system drive arrived, I then installed Vista on that drive, but didn’t reformat the original disk as I’d already recorded some programmes that I wanted to keep.

    This meant that there was the old “Program Files”, “Windows” and other directories that Windows creates. The problem is that even running with UAC you can’t delete them. If I’d reformatted the drive, I would have never had this problem.

    Tim Sneath went through a similar situation, and his solution worked for me too.