Config Fun

InstallUtil, Windows Services & ProjectInstallers with App.Config Settings

Config Fun
Config Fun
We had a situation in work where we needed to make service installation a more configurable process.

So a very simple example, In order to install a .NET Windows Service we need to provide it with a username & password that the services will run as. We can either provide that information at installation time, or through the following properties in the ProjectInstaller.cs file for your service.

However in an environment where multiple developers are working on a service, particularly a service that requires elevated privileges and needs to run as a specific account, this can be a royal pain.

private void InitializeComponent()
{
    this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
    this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();

    this.serviceProcessInstaller1.Username = "MYPC\JohnSmith";
    this.serviceProcessInstaller1.Password = "abcd1234";

    this.serviceInstaller1.ServiceName = "My Service";
    this.serviceInstaller1.Description = "My Description";

    this.Installers.AddRange(new System.Configuration.Install.Installer[] {
	this.serviceProcessInstaller1,	this.serviceInstaller1});
}

Option 1. Type in the credentials every time the service is Installed/Started… a not-so-ideal manual process when constantly re-starting a service to debug. It’s also a pain for an automated xcopy releases where there is one big batch job which will stop, uninstall, reinstall & re-start every service in the deployment.

Option 2. Leave the account credentials hard-coded in. This isn’t ideal either. With Local Dev Environments, Shared Development Environments and Staging & Production platforms, it’s too easy to leave the wrong credentials hardcoded into the ProjectInstaller, or worse, introduce a small typo/bug when the values are changed/recompiled between environment releases.

Wouldn’t it be better if this could be configurable ?

Unfortunately, we need to do a little gymnastics in order to gain access to the .config file of the service at installation time when using InstallUtil.exe. The App.config Configuration File which the ConfigurationManager is using during the installation process is actually InstallUtil.exe.config… not what we want. Instead, we can manually load the associated configuration file for the assembly which contains the Project Installer, and retrieve our settings from that.

private static string GetConfigurationValue(string key)
{
    var service = Assembly.GetAssembly(typeof(ProjectInstaller));
    Configuration config = ConfigurationManager.OpenExeConfiguration(service.Location);
    if (config.AppSettings.Settings[key] == null)
    {
        throw new IndexOutOfRangeException("Settings collection does not contain the requested key:" + key);
    }

    return config.AppSettings.Settings[key].Value;
}

We can now add our installation information to the configuration file which is template controlled under our release process.

private void InitializeComponent()
{
    this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
    this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();

    this.serviceProcessInstaller1.Password = GetConfigurationValue("ServicePassword");
    this.serviceProcessInstaller1.Username = GetConfigurationValue("ServiceUserName");

    this.serviceInstaller1.ServiceName = "Service Name";
    this.serviceInstaller1.Description = "Service Description - " + GetConfigurationValue("ServiceLabel"); 
    //E.g. ServiceLabel = "LOCAL EOINC";

    this.Installers.AddRange(new System.Configuration.Install.Installer[] {
	this.serviceProcessInstaller1,
	this.serviceInstaller1});
}

The usual caveats about config file encryptions and protecting your passwords apply.

11 comments on “InstallUtil, Windows Services & ProjectInstallers with App.Config Settings

  1. Francis Lorenz

    This is exactly what I am looking for, in my case to configure a custom service name each time I install the service (may be installed several times on the same server), except that it doesn’t work for me! Too bad…
    I think the point is the difference between the so-called “Dynamic Properties” and “Application Settings” mechanisms.
    Using “Dynamic Properties”, the settings are stored in app.config as a series of key-value pairs:

    Using “Application Settings”, you define strongly typed settings in the Properties “Settings” tab and they are reflected in the app.config as a series of “setting” items:

    PROGIN_FLM_Remote

    I think your nice solution fits to the “Dynamic Properties” model.
    So my question is, would you have some equivalent solution for the “Application Settings” model, which I am using?

  2. Eoin

    No bother guys, glad it helped…

    Francis, if the settings are in the config file, then it should just be a matter of loading the correct configuration section and iterating though it’s contents. If you want to post an example of your config file. I can take a look.

  3. Pingback:.NET Windows Services – Tips & Tricks » try { } catch { } me | try { } catch { } me

Leave a Reply

Your email address will not be published. Required fields are marked *