Configuration Merge Behavior

.NET Configuration Merge Default Behavior

General Behavior

In general, the .NET configuration system operates as a hierarchical view of an application’s configuration expressed in XML.  The hierarchy of the view takes on two dimensions:  an XML hierarchy (nodes have parents and children) to organize the data; and multiple configuration files (i.e. machine.config, app.config, and web.config) whose contents merge together to provide a final view of an application’s configuration.  This document intends to describe the later of the two hierarchies and help the reader understand the expected semantics around the merging of these files.

Configuration Sections and Elements

Configuration sections and elements follow the same merging semantics, with one exception detailed below.  For simplicity’s sake this document will describe the merging semantics for configuration elements since all rules that apply to elements also apply to sections.  Since this exception only applies to configuration sections, this document will explicitly describe that behavior as applying to a section.

 

For configuration elements, the merging behavior follows an override semantic where the configuration file closest to the application “wins”.  For non-WebHosted applications the configuration file load order starts with the machine.config file and then merges the appropriate app.config file to produce the final configuration view for the application.  This simply means that elements in app.config will overwrite elements in machine.config.  The appropriate app.config file defaults to an application’s executable file name postfixed with “.config”.  For example, “MyApplication.exe” will have a default app.config file “MyApplication.exe.config”.

 

For WebHosted applications the answer becomes a bit more complex since web.config files may be nested themselves.  In this case the load order starts with machine.config, then merges the root web.config for the machine, then adds the web.config at the application’s VROOT (if it exists), and then walks the directory tree from the VROOT down to the application’s current directory looking for any additional web.config files to merge.  As this merge happens, any duplicate elements found along the way overwrite the previous settings, thus the configuration file closest to the application “wins”.

 

This describes the general, default behavior for configuration element merging.  However, for completeness, two special mechanisms need discussion here:  locking, and “allow definition”.  The locking mechanism allows a configuration owner to lock an element(s) and/or property(ies).  If a subsequent configuration file attempts to overwrite a locked element or property, the configuration system throws an exception.  Configuration owners should use this mechanism to prevent downstream configuration files from modifying settings.

 

The “allow definition” mechanism only applies to configuration sections and allows configuration developers to limit the locations where a section may appear.  WCF makes use of this mechanism to limit the appearance of certain configuration sections to machine.config only.  Further details of these elements appear below under WCF Configuration Merge Behavior – Configuration Elements.  If a configuration file contains a section outside of its “allow definition” scope the configuration system throws an exception, halting the merge at that point.

Configuration Collections

.NET configuration collections come in four different base types; BasicMap, AddRemoveClearMap, BasicMapAlternate, and AddRemoveClearMapAlternate.  Each collection type follows its own merge semantic regarding non-duplicate elements detailed below.  Collections handle duplicate elements specially.  Each collection type defines a default behavior, again detailed below, but also allows for configuration developers to change that behavior simply by overriding the virtual property ThrowOnDuplicates.  When ThrowOnDuplicates returns true, a collection will throw an exception if the merged configuration view attempts to add a duplicate element.  When ThrowOnDuplicates returns false, the addition of a duplicate element into a collection will result in the second element overwriting the first element (i.e. last one in wins).

 

In the case that duplicate elements exist in the same configuration file, the configuration system reads these collections from top to bottom.  This means that the element listed first will be added to the collection first, and the later element will encounter the same merge semantic as if it came from a later configuration file (i.e. if ThrowOnDuplicates returns true an exception will be thrown, else the later element overwrites the first).

BasicMap Collections

BasicMap type collections are additive only.  That means that once an element is added to the collection, it cannot be removed by a later configuration file, nor can the collection be cleared.  BasicMap collections return false for ThrowOnDuplicates as a default.  This means that although a later configuration file cannot remove an element, it can overwrite an element.

AddRemoveClearMap Collections

AddRemoveClearMap type collections are collections that support add, remove, and clear functionality.  This means that once added to a collection, later configuration files may remove an element from the collection with a <remove> tag.  Also, a configuration file can insure that a collection starts empty by including a <clear> tag.  Since they support explicit removal of elements, AddRemoveClearMap collections return true for ThrowOnDuplicates as a default.

Alternate Collections

The “Alternate” prefix for both collection types simply refers to a change in the collection ordering. Normally, the deserialization process postfixes new collection items; adding an element places it at the end of the list. For collections whose items span multiple configuration files (i.e. machine.config and app.config), this results in items contained in later configuration files always showing up at the end of the collection. For collections where ordering affects behavior (i.e. registering importers where the first importer that can handle a request halts further processing), this solution could result in app.config entries never affecting the product.

In alternate configuration maps, deserialization preserves collection ordering within a configuration file, but essentially reverses the ordering of the files. This means that app.config entries exist before machine.config entries. For example, given a configuration collection <behaviorExtensions> with machine.config entries:

<behaviorExtensions>

  <add name="a" type="TypeA"/>

  <add name="b" type="TypeB"/>

</behaviorExtensions>

and app.config entries:

<behaviorExtensions>

  <add name="c" type="TypeC"/>

  <add name="d" type="TypeD"/>

</behaviorExtensions>

If this collection were either a BasicMap or AddRemoveClearMap (i.e. not an Alternate collection), the resulting merged collection would look like:

<behaviorExtensions>

  <add name="a" type="TypeA"/>

  <add name="b" type="TypeB"/>

  <add name="c" type="TypeD"/>

  <add name="d" type="TypeD"/>

</behaviorExtensions>

However, if this were an Alternate collection type the resulting merged collection would look like:

<behaviorExtensions>

  <add name="c" type="TypeD"/>

  <add name="d" type="TypeD"/>

  <add name="a" type="TypeA"/>

  <add name="b" type="TypeB"/>

</behaviorExtensions>

Notice that in the Alternate collection the merged view preserves ordering within each file; however, reverses the ordering of those files.

WCF Configuration Merge Behavior

General Behavior

Except where noted specifically below, the WCF configuration merge behavior follows the .NET configuration merge behavior exactly.

Configuration Elements

WCF configuration only contains two sections that use the “allow definition” mechanism to limit their valid locations:  system.serviceModel/commonBehaviors and system.serviceModel/machineSettings.  In both cases, the sections limit their location to machine.config, preventing app.config and web.config owners from including their own values, or overwriting machine.config settings.

 

The common behaviors section includes two children collections of behaviors intended to apply to all services and endpoints on the local machine respectively.

 

The machine settings section includes machine specific settings for WCF.  Currently, this only includes the machine wide switch enableLoggingKnownPii.  This turns on the ability for app.config and web.config owners to turn on logging of PII in their own applications by flipping on the logKnownPii switch on their trace source.

Configuration Collections

WCF configuration collections can be broken into three distinct categories:  collections that inherit from ConfigurationElementCollection, ServiceModelEnhancedConfigurationElementCollection, and custom collections.  Collections that inherit from ConfigurationElementCollection follow the .NET configuration collection merge semantics and a detailed table follows the discussion of custom collections.

 

Collections that inherit from ServiceModelEnhancedConfigurationElementCollection follow the .NET configuration collection merge semantics with one difference.  These collections keep track of whether or not a duplicate entry exists within the same configuration file.  If the duplicate entries exist in the same configuration file, the collection throws an appropriate exception.  If the duplicate entries exist in different configuration files, the collection follows the appropriate semantic based on the value of the ThrowOnDuplicates property.  The following WCF configuration collections inherit from ServiceModelEnhancedConfigurationElementCollection:

 

XPath Location of Collection

system.serviceModel/behaviors/endpointBehaviors

system.serviceModel/behaviors/serviceBehaviors

system.serviceModel/bindings/XXX

system.serviceModel/client

system.serviceModel/client/metadata/policyImporters

system.serviceModel/client/metadata/wsdlImporters

system.serviceModel/comContracts

system.serviceModel/comContracts/exposedMethods

system.serviceModel/comContracts/persistableTypes

system.serviceModel/comContracts/userDefinedTypes

system.serviceModel/services

system.serviceModel/services/service

 

 

Custom collections are configuration elements that implement the ICollection interface directly.  These collections have much more control over the merge semantics of their collection, but require significantly more code.  The WCF configuration contains five such collections:  the common endpoint behavior element, the common service behavior element, the endpoint behavior element, the service behavior element, and the custom binding element.  All of these elements required the custom implementation because the collections do not have foreknowledge of the complete set of xml tag names valid for the contained elements.  However, the merge semantics are simplified because of their location in the configuration xml tree. 

 

The behavior element collections exists in either the appropriate child collection of the commonBehaviors section (which can only exist in machine.config, so there is no merging), or as an element in the appropriate behaviors collection (appropriate behaviors collection refers to either the service or endpoint behaviors).  As an AddRemoveClearMap that does not throw on duplicates (see table below), the behaviors collections will override an entire behavior element when a duplicate exists.  This prevents the behavior element collections from ever encountering a condition that requires any sort of merge.

 

Likewise, the custom binding element collection never encounters a merge condition because the customBinding collection also exists as an AddRemoveClearMap that does not throw on duplicates.

 

The following table describes the configuration objects that inherit from ConfigurationElementCollection within System.Runtime.Serialization.dll and System.ServiceModel.dll in terms of the collection type (BasicMap vs. AddRemoveClearMap) and value returned by ThrowOnDuplicates.  For details on how these values affect a collection’s merge semantics see Configuration Collections above.

 

XPath Location of Collection

Collection Type

ThrowOn

Duplicates

system.runtime.serialization/dataContractSerializer/declaredTypes

AddRemove

ClearMap

True

system.runtime.serialization/dataContractSerializer/declaredTypes/add

BasicMap

False

system.runtime.serialization/dataContractSerializer/declaredTypes/add/add

BasicMap

False

system.runtime.serialization/dataContractSerializer/declaredTypes/add/add/add

BasicMap

False

system.serviceModel/extensions/behaviorExtensions

BasicMap

True

system.serviceModel/extensions/bindingElementExtensions

BasicMap

True

system.serviceModel/extensions/bindingExtensions

BasicMap

True

system.serviceModel/behaviors/endpointBehaviors

AddRemove

ClearMap

False

system.serviceModel/behaviors/serviceBehaviors

AddRemove

ClearMap

False

system.serviceModel/behaviors/endpointBehaviors/behavior/

clientCredentials/issuedToken/issuerChannelBehaviors

AddRemove

ClearMap

True

system.serviceModel/behaviors/endpointBehaviors/behavior/

clientCredentials/serviceCertificate/scopedCertificates

AddRemove

ClearMap

True

system.serviceModel/behaviors/serviceBehavior/behavior/

serviceAuthorization/authorizationPolicies

AddRemove

ClearMap

True

system.serviceModel/behaviors/serviceBehavior/behavior/

serviceCredentials/issuedTokenAuthentication/knownCertificates

AddRemove

ClearMap

True

 

XPath Location of Collection

Collection Type

ThrowOn

Duplicates

system.serviceModel/bindings/XXX

AddRemove

ClearMap

False

system.serviceModel/bindings/customBinding/binding/security/

issuedTokenParameters/additionalRequestParameters

BasicMap

False

system.serviceModel/bindings/customBinding/binding/security/

issuedTokenParameters/claimTypeRequirements

AddRemove

ClearMap

True

system.serviceModel/bindings/customBinding/binding/security/

secureConversationBootstrap/issuedTokenParameters/

additionalRequestParameters

BasicMap

False

system.serviceModel/bindings/customBinding/binding/security/

secureConversationBootstrap/issuedTokenParameters/

claimTypeRequirements

AddRemove

ClearMap

True

system.serviceModel/bindings/wsFederationHttpBinding/binding/

security/message/claimTypeRequirements

AddRemove

ClearMap

True

system.serviceModel/bindings/wsFederationHttpBinding/binding/

security/message/tokenRequestParameters

BasicMap

False

system.serviceModel/client

AddRemove

ClearMap

False

system.serviceModel/client/metadata/policyImporters

AddRemove

ClearMap

False

system.serviceModel/client/metadata/wsdlImporters

AddRemove

ClearMap

False

system.serviceModel/comContracts

AddRemove

ClearMap

False

system.serviceModel/comContracts/exposedMethods

AddRemove

ClearMap

False

system.serviceModel/comContracts/persistableTypes

AddRemove

ClearMap

False

system.serviceModel/comContracts/userDefinedTypes

AddRemove

ClearMap

False

system.serviceModel/diagnostics/messageLogging/filters

AddRemove

ClearMap

True

system.serviceModel/serviceHostingEnvironment

AddRemove

ClearMAp

True

system.serviceModel/services

AddRemove

ClearMap

True

system.serviceModel/services/service

AddRemove

ClearMap

False

system.serviceModel/services/service/host/baseAddresses

BasicMap

True

system.serviceModel.activation/netPipe/allowAccounts

AddRemove

ClearMap

True

system.serviceModel.activation/netTcp/allowAccounts

AddRemove

ClearMap

True