Tuesday, May 31, 2011

Adding more config files by project build type

As people have already noticed that in .Net 4.0 web project, there are multiple versions of Web.config file such as Web.Debug.config and Web.Release.config. Developers can also add more files like this for e.g ConnectionStrings.config can also have ConnectionStrings.Debug.config and ConnectionStrings.Release where Debug and Release are Configuration of a project.

Lets look at the scenario where we would want to add ConnectionStrings file version so it uses the proper config file depending on the project build configuration type.

Step 1 – Add new ConnectionString files to your project

Add 4 configuration file to your project as follows:

- ConnectionStrings.config
- ConnectionStrings.Template.config
- ConnectionStrings.Debug.config
- ConnectionStrings.Release.config

File for debug and release contents will look like following:

<?xml version="1.0" encoding="utf-8" ?>
<connectionStrings xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="Replace">
  <add name="MyConnectionString" connectionString="Address=[server],1433;Database=[database];UID=[user];PWD=[password];"/>
</connectionStrings>





You can add as many connection strings depending on which build type you want them to be associated with in its respective file. Like ConnectionStrings.Debug.config will contain connection strings to our development environment which we want to use in “Debug” mode.


ConnectionStrings.Release.config will contain connection strings to our production environment when we build the project for “Release”.


For now, file ConectionStrings.Template.config contents don’t have to have any connection strings in it since it’ll be used as a template to create ConnectionString.config file. You can add connection string in this file if they are not specific to a project build type and you always want them to be there. But for now, it’ll be empty like following:


<?xml version="1.0"?>
<!-- connection strings -->
<connectionStrings>
  
</connectionStrings>



Step 2 – Update project file


We are going to add some xml to the project file so Visual Studio build knows how to associate different ConnectionString files together. Also, Visual Studio will show connection string files in a nested tree in solution explorer.


We’ll add some build tasks so Visual Studio uses the proper ConnectionString file depending on the project build type.


Right click on project node in solution explorer and choose unload project option. This allows you to open project xml file and update it. Right click again and choose Edit [Project.csproj]. You’ll notice that xml file for project will appear for edit.


Under /Project/ItemGroup, Add Following:


<Content Include="App_Config\Server\ConnectionStrings.config">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <None Include="App_Config\Server\ConnectionStrings.Template.config" />
    <None Include="App_Config\Server\ConnectionStrings.Debug.config">
      <DependentUpon>ConnectionStrings.Template.config</DependentUpon>
    </None>
    <None Include="App_Config\Server\ConnectionStrings.Release.config">
      <DependentUpon>ConnectionStrings.Template.config</DependentUpon>
    </None>



This tells visual studio to show debug and release files for connection string nested under ConnectionStrings.Template.config node in solution explorer. Please note that we are assuming that connection string config files are saved under /[ProjectFolder]/App_Config/Server folder.


Next, to the very bottom of project xml file under /Project, below <import> tag(s) add:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />



This lets you use TransformXml task which we’ll use below.


Under this “UsingTask” node add:


<Target Name="ConfigConnectionStrings" Condition="Exists('./App_Config/Server/ConnectionStrings.$(Configuration).config')">
  <Delete Files="./App_Config/Server/ConnectionStrings.config" />
  <TransformXml Source="./App_Config/Server/ConnectionStrings.Template.config" Destination="./App_Config/Server/ConnectionStrings.config" Transform="./App_Config/Server/ConnectionStrings.$(Configuration).config" />
</Target>
<Target Name="BeforeBuild">
  <Copy SourceFiles="./App_Config/Server/ConnectionStrings.Template.config" DestinationFiles="./App_Config/Server/ConnectionStrings.config" />
  <CallTarget Targets="ConfigConnectionStrings" />
</Target>



The above piece tells Visual Studio to delete ConnectionStrings.config file so we always have a new copy created whenever we build the project and there are no read/write issues. Then it instructs the project build to transform the appropriate connection string file based on project build type.


It also adds  “BeforeBuild” target which copies the empty ConnectionStrings.Template.config file as ConnectionStrings.config which we’ll fill based on the project build type.


Right after the copy, it directs the project build to call the ConfigConnectionStrings target which performs the delete of older ConnectionStrings.config copy and does the transformation.


Now once you save your project file and right click on project node in solution explorer, choose “reload project” option to load the project along with all its files in solution explorer.


Step 3 – Add external ConnectionString file reference to web.config


To keep connection strings outside of the web.config file, we have to add the following line under /configuration node.


 <connectionStrings configSource="App_Config\Server\ConnectionStrings.config" />



Step 4 – Excluding ConnectionStrings.config file from project


Last but not least, we have to exclude ConnectionStrings.config file from the project list in solution explorer so it can be deleted/created by project build. Since we are using svn at work, we have to do an additional step to ignore the file from svn. If you are using AnkhSvn Visual Studio plug-in, you can right click on ConnectionStrings.config file and go to Subversion > Ignore > Ignore File (ConnectionStrings.config) option.


That’s it folks, now when you build the project, you’ll see a new copy of ConnectionStrings.config file created with your connection strings based on your project build type.