views:

736

answers:

2

For one client, I have to deliver a build they use in QA and production. The checksum of the build file has to match - it cannot change at all between QA and production. The configuration for each environment is different, so I have a build that contains just the code and then a separate build for each environment that contains just the environment specific config files. The config file builds puts the files in the same location regardless of environment, so the code can always load c:\myapp\myconfig.xml which will contain the settings for that environment. Most articles I read about this (such as Scott Hanselman's) involve different builds for each environment, but this won't work because the checksum values will be different. Should I deploy these config files some other way, or do I have a viable solution? The one problem with my current solution is it requires multiple config files that are nearly identical but not quite. One change therefore has to be added to multiple files, which is something I would like to avoid, but I don't know how to do it except at build time or with an external script that copies the proper file.

A: 

Assuming:

1) XML config files

2) Total number of changes between builds are few (even if copied to many config files)

I would have the installer handle updating the config files at install time

For instance we use WiX v3 for our installer and update several config files with values during install using the XmlFile element

<util:XmlFile Action="setValue" File="[DIRECTORIES.WEBSERVICES]web.config" ElementPath="//configuration/system.web/compilation" Name="debug" Value="false" Permanent="yes" />

Rob McCready
+1  A: 

Not sure if your setup is more complicated, but we have a similar problem and we added a custom actions class that updates the config files based on the environment (which the user selects during installation), then you add this custom actions project to your setup project. That way you use one setup exe no matter what environment you're installing to.

Let me know if you're interested and I can post some samples or more info on how we accomplished it.

Here are some more details:

  1. Add a new dialog to your Setup project to request the environment from the user (we use a 4 radio button dialog with the 4 environments we have: dev, qa, staging and production)
  2. Configure the values of the 4 radio buttons and the property that this value will be setting i.e. "environment" (to latter be used by the CustomActions class)
  3. Add a dll project to your solution with a single class (CustomActions)
  4. in the CustomAction class, you read the property we configured in step two as:

     if(!this.Context.Parameters.ContainsKey("environment"))
     {
      string error = "'environment' argument is null. Please configure config file manually";
      //...handle your error, etc.
      return;
     }
    
    
    
    string env = this.Context.Parameters["environment"];
    
  5. now your env variable contains the value we assigned to each radio button in step. You then can use a switch statement to decide what environment the user selected. and update your config file appropriately with:

Configuration config = ConfigurationManager.OpenExeConfiguration(this.servicePath); //for example, to change your connection strings you'd use: config.ConnectionStrings.ConnectionStrings["oracle"] = "dev conn string here";

  1. Back in your setup project, add the output of the CustomActions project to your CustomActions editor (View menu -> Editor -> Custom Actions)

  2. Finally, configure the CustomActionData property of your setup project to pass the environment and other variables to the CustomAction class (mine looks something like this: /serviceFolder="[TARGETDIR]\" /serviceExe="blahblah.exe" /serviceName="MyServiceName" /environment="[ENVIRONMENT]"

Hope that makes sense and applies to your solution!

Ricardo Villamil
This sounds interesting - would you post more information? How do you use that class in the setup project?
Tai Squared