views:

3827

answers:

6

I have three custom build configurations { Dev, Qs, Prd }. So, I have three app configs { Dev.config, Qs.config, Prd.config }. I know how to edit the .csproj file to output the correct one based on the current build configuration.

<Target Name="AfterBuild">
   <Delete Files="$(TargetDir)$(TargetFileName).config" />
   <Copy SourceFiles="$(ProjectDir)$(Configuration).config" DestinationFiles="$(TargetDir)$(TargetFileName).config" />
</Target>

My problem is, I need to have six build configurations { Dev, Qs, Prd } x { Debug, Release }. I need to support the debug and release settings (optimizations, pdb, etc) for each environment. However, the app config values don't change between debug/release.

How do I keep the build script as generic as possible and use only the three app configs? I don't want to hard code too many conditional strings.

A: 

The last solution I would like to employ is to create 6 app configs, 1 per custom configuration

{ Dev_Debug.config, Dev_Release.config, Qs_Debug.config, ... , Prd_Release.config }.

Although, with that setup, I could maintain the generic build script, using no conditional strings.

Anthony Mastrean
+3  A: 

Something along the lines of

<PropertyGroup Condition="'$(Configuration)'=='Dev_Debug' OR '$(Configuration)'=='Dev_Release'" >
    <CfgFileName>Dev</CfgFileName>
</PropertyGroup>
<!-- similar for Qs & Prd -->
<Target ...>...$(CfgFileName).config...
Brian
This works until I add the 3rd custom build config. I get an error: cannot find <blah>\.config. I think this may be a problem with my environment. I question whether I want to maintain this much .csproj config though.
Anthony Mastrean
A: 

I suggest that your question reveals that you have outgrown app.config--it is time to move on to a better solution, and to begin addressing some related issues.

For one, you should NEVER automatically deploy a configuration file to production, and you should expect the operations support personnel to vehemently reject any attempt to do so. Of course, if you are the operations support personnel, then you should reject it yourself. Instead, your release should include some instructions for manually updating the configuration file, with a sample for illustration. Production configuration is too important for lesser measures, unless you simply don't value your production system much.

Likewise for test and other environments, but to a lesser degree, so you really only need your app.config populated for your own development work.

An option is to embed the multiple configurations into a single app.config, which is reasonable for small, relatively unimportant applications or in early stages of development/release. For example, create a configuration setting called something like target-env that contains a value that you use in your code to select other configuration settings, such as by prepending the value onto the keys of the other configuration settings.

My preference is to move past app.config altogether, or to use it minimally. In this case, I prefer to put just enough configuration data into a file to allow my application/system to connect to its database(s), then I put the remaining configuration details into a special database table for that purpose. This has lots of advantages, such as making the database "aware" of what environment it represents (dev, test, production, etc.) and keeping the configuration and the other data together. The deployment package can then properly be kept dumb regarding configurations and environment differences--the code just accesses its configuration data and acts accordingly, so the same deployment package is good for any environment.

However, a key success factor to this approach is that your application code must "know" what it expects for configuration and it must "know" to reject an improper/incomplete configuration. This is where you should spend your time, not trying to work around the limits of app.config.

That usually means creating your own class for accessing configuration data, then using that class throughout your application instead. This also leads to many other benefits, such as strongly-typed configuration data: instead of a String, return a DateTime, or a Url, or an Integer, or a Currency, or whatever best fits the configuration data and the application.

Rob Williams
There are 10-15 config items: a URL, a list of remote objects, a list of files. I am separating the source of config from the format by interface. The app config is the likely and expected source.I prefer manual update as part of the build process, but I have to investigate this path for my boss.
Anthony Mastrean
"For one, you should NEVER automatically deploy a configuration file to production" Try telling that to Microsoft! Some of the stuff they stick in the app/web.config file these days really ought to be compiled into the exe file.
Martin Brown
Yes, well I have found it fruitless to try telling Microsoft anything--I just try to protect myself and my client from the impact. This is a perfect illustration of the necessary changes when you make the transition to an enterprise-class deployment.
Rob Williams
+4  A: 

We fixed this using the Choose element in the csproj file. We have several different configurations set up so all we do is drop this block into your proj file and you can use VS's Configuration to help you out. I do want to second Rob's advice to move passed app.config. I have been moving in that direction for some time.

  <Choose>
<When Condition=" '$(Configuration)' == 'Debug' ">
  <ItemGroup>
    <None Include="App.config" />
    <None Include="Release\App.config" />
  </ItemGroup>
</When>
<Otherwise>
  <ItemGroup>
    <None Include="Release\App.config">
      <Link>App.config</Link>
    </None>
  </ItemGroup>
</Otherwise>

Steve
+5  A: 

Here is a nice Discussion at scott Hanselmans about automating the multiple configuration.

In the comments section there are some alternative solution's. Some interesting like working with delta of the config files. Some other are like having different config files for different environment.

Biswanath
+1  A: 

How about using a build server?
Its been a long time since I've worked in .NET but can't you use Hudson(-like) server for managing your build configurations? Isn't it easier?
And what about NAnt? Doesn't it suit your needs?

Nimrod Shory
James, you're right. At this point, we've outgrown the capabilities (and sensibilities) of using the csproj file.
Anthony Mastrean