Share via


Common Configurations

Applies to: Windows Communication Foundation

Published: June 2011

Author: Alex Culp

Referenced Image

This topic contains the following sections.

  • Common Configuration Across Environments
  • Common Configuration Across Services
  • Common Configuration Across Services and Environments
  • Choosing a Configuration Strategy

Common Configuration Across Environments

After you separate a Web.config file into multiple configuration files, you will notice that some of portions of the configuration are specific to a service, but not to any particular environment. A good example of this is in the services configuration for System.ServiceModel. The following figure illustrates this scenario.

Referenced Image

You do not need to make changes to these files unless you can make them common to all services and environments. For example, the services configuration is unlikely to change from one environment to another. After you move the configuration to a configuration source, you should not have to make changes to it in more than one location. The following XML code is an example of how to move the configuration to a configuration source.

<system.serviceModel>
  …
  <services configSource="Config\services.config"/>
  …
</system.serviceModel>

Common Configuration Across Services

When you have multiple services, some parts of the configuration will be identical for all services, but vary by environment. For example, ten services might use one database. If you upgrade to a new server, you will need to change each of these files. The following figure illustrates this situation.

To centralize any configuration that is common to all services, you must create a master source for all configuration information, and use a script to copy the files to that destination. You can use some of the same techniques that are demonstrated in "Configuring a Single Service Across Multiple Environments." However, the current scenario moves configuration information that is common to all services to a central project. You will only need to maintain a master copy.

Steps to Centralize Configuration that Is Common to All Services

The following example uses Visual Studio to centralize the configuration that is contained in a behaviors configuration file. Behavior configuration information is a good candidate for centralization because it is often shared across services. You can modify the following procedure so that it meets your own requirements.

  1. In Visual Studio, create a build configuration for each of your environments. Do not forget the Debug configuration for the local developer workstation. For more information about how to set up build configurations, see "Configuration Manager Dialog Box" at https://msdn.microsoft.com/en-us/library/t1hy4dhz(v=VS.100).aspx.

  2. Click Empty Project to create a new project. Name it CentralizedConfig, or any name that you choose. Create the project.

  3. In Solution Explorer, right-click the project, and select Properties. Click the Application tab. In the Output Type list, click Class Library (console and Windows applications require an entry point, which is unnecessary in this scenario).

  4. Add a Behaviors.config file at the root of the CentralizedConfig project.

  5. Create an environment-specific configuration file for each environment, including Debug. The following figure illustrates an example of the hierarchy.

    Referenced Image

  6. You might be a bit overwhelmed by the number of configuration files. You can group these files under the root environment configuration file. Open the .csproj file in Notepad or another text editor, and find the behaviors file. The following XML code is an example of what it should like.

      <ItemGroup>
        <None Include="Behaviors.config" />
        <None Include="Behaviors.Debug.config" />
        <None Include="Behaviors.DEV.config" />
        <None Include="Behaviors.QA.config" />
        <None Include="Behaviors.PROD.config" />
      </ItemGroup>
    

    To group these files, add a DependentUpon element to each of the environment-specific configuration files (Debug, DEV, QA, and PROD). The following XML code is an example of the edited configuration file.

      <ItemGroup>
        <None Include="Behaviors.config" />
        <None Include="Behaviors.Debug.config" >
            <DependentUpon>Behaviors.config</DependentUpon>
        </None>
        <None Include="Behaviors.DEV.config" >
            <DependentUpon>Behaviors.config</DependentUpon>
        </None>
        <None Include="Behaviors.QA.config" >
            <DependentUpon>Behaviors.config</DependentUpon>
        </None>
        <None Include="Behaviors.PROD.config" >
            <DependentUpon>Behaviors.config</DependentUpon>
        </None>
      </ItemGroup>
    
  7. Go back to Visual Studio and reload the project. The following figure illustrates the CentralizedConfig project structure.

    Referenced Image

  8. In order for the transformation to work in a configuration source, you must add a namespace reference to the document transform XSD. Open the Behaviors.Debug.Config file and add the following XML code.

    <behaviors xmlns:xdt="https://schemas.microsoft.com/XML-Document-Transform">
      <serviceBehaviors>
      </serviceBehaviors>
    </behaviors>
    
  9. You can now add a configuration transformation for each behavior that differs from the default configuration. For example, in a production build, you might not want to expose the service metadata or the exception details, so you can transform the default behavior to hide them. The following XML code is an example of what the transformation looks like.

    <behaviors xmlns:xdt="https://schemas.microsoft.com/XML-Document-Transform">
      <serviceBehaviors>
        <behavior xdt:Locator="not(@name)"><!--Find default behavior (the one with no name)-->
          <serviceMetadata httpGetEnabled="false" xdt:Transform="SetAttributes(httpGetEnabled)" />
          <serviceDebug includeExceptionDetailInFaults="false" xdt:Transform="SetAttributes(includeExceptionDetailInFaults)"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
  10. Edit all of the other environment-specific configuration files, as you did in previous steps. Open the CentralizedConfig .csproj file in a text editor.

  11. At the top of the project file, just under the project node, add the following line of XML code.

    <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
    
  12. At the bottom of the file is a set of commented out build targets. Uncomment them and add the following configuration transformation step.

      <Target Name="AfterBuild">
          <!-- Transform and copy Behaviors configuration -->
          <TransformXml Source="$(ProjectDir)Behaviors.config" Transform="$(ProjectDir)Behaviors.$(ConfigurationName).config" Destination="$(SolutionDir)WCFService1\Behaviors.config" />
          <Copy SourceFiles="$(SolutionDir)WCFService1\Behaviors.config" DestinationFiles="$(SolutionDir)WCFService2\Behaviors.config" />
          <Copy SourceFiles="$(SolutionDir)WCFService1\Behaviors.config" DestinationFiles="$(SolutionDir)WCFService3\Behaviors.config" />
      </Target>
    
    NoteNote

    Alternatively, you can use the TransformXml task for each service rather than the Copy command. However, the command is more appropriate because the transformation only happens once.

    <Target Name="AfterBuild"> <!-- Transform and copy Behaviors configuration --> <TransformXml Source="$(ProjectDir)Behaviors.config" Transform="$(ProjectDir)Behaviors.$(ConfigurationName).config" Destination="$(SolutionDir)WCFService1\Behaviors.config" /> <TransformXml Source="$(ProjectDir)Behaviors.config" Transform="$(ProjectDir)Behaviors.$(ConfigurationName).config" Destination="$(SolutionDir)WCFService2\Behaviors.config" /> <TransformXml Source="$(ProjectDir)Behaviors.config" Transform="$(ProjectDir)Behaviors.$(ConfigurationName).config" Destination="$(SolutionDir)WCFService3\Behaviors.config" /> </Target>

  13. Build your solution with the build configuration of your choice.

  14. From the Project menu, select Show All Files.

  15. You should now see a Behaviors.config file at the root of each of your services. The following figure illustrates an example of the project structure.

    Referenced Image

Common Configuration Across Services and Environments

A configuration file that is common to services and environments is an ideal candidate for centralization. The following figure illustrates this situation.

Referenced Image

Choosing a Configuration Strategy

In general, if you have many services that share a common configuration, you should try to centralize the information to avoid duplication. If you have separated the configuration information into separate configuration sources, you can apply a different strategy to each configuration source. The following table lists some configuration sources, and the best strategy to apply.

Table 1. Example Configuration Sources and Possible Approach

Configuration Source

Configuration Strategy

Service Model: bindings

Centralized configuration

Service Model: client endpoints

Centralized configuration by environment

Service Model: behaviors

Centralized configuration by environment

Service Model: services

Configuration by environment

Connection Strings

Centralized configuration by environment

Application Settings

No centralization or centralization by environment

Enterprise Library Exception Handling Application Block

Centralized configuration by service

Enterprise Library Logging Application Block

Centralized configuration by service

Enterprise Library Unity Configuration

No centralization

Planning the Centralization Effort

Centralization can take several man weeks of development time, depending on the number and complexity of your services. In addition, it is quite possible that the services will be disrupted. This is because centralization affects builds, and it may even break some services. To mitigate some of the risks, create a new source-code branch where you can make and test the changes.

Implementing these Techniques in an Existing Enterprise Services Solution

While centralization is worth the effort in the long term, it is very time consuming. As you migrate your solution, there will probably be times when developers who are not involved with the migration will be unable to work. Migrate the solution during a slack period, and not when you are in a critical phase of a project.

Previous article: Configuring a Single Service Across Multiple Environments

Continue on to the next article: Simplifying Enterprise Library Configuration