How to conditionally deploy an app.config based on build configuration?

27,387

Solution 1

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...

Solution 2

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>

Solution 3

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.

Solution 4

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?

Share:
27,387
Anthony Mastrean
Author by

Anthony Mastrean

Updated on July 23, 2022

Comments

  • Anthony Mastrean
    Anthony Mastrean almost 2 years

    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.