I recently had a co-worker inquire about using different configuration sources across different application blocks within the Enterprise Library. As has already been demonstrated (both in the EntLib documentation and on various websites), it's extremely simple to modify the source of configuration information for the entire Enterprise Library. This is provided both by the EntLib framework and the configuration tool. Simple create a new/alternate Configuration Source, set it as the default configuration source, and away you go. You can use one of the out-of-the-box configuration sources (alternate file source, e.g.) or write your own (put configuration in Sql, a flat file, registry, or whatever you can conjure up).
However, splitting configuration between different application blocks is slightly different. It's not truly natively supported by EntLib, but the pieces needed to achieve this are present in the framework, and the customization required to pull it off is extremely straightforward.
To demonstrate, I'll pull configuration for a single application block from a separate configuration file. In theory, and as I described earlier, this can be from any source for which a ConfigurationSource provider exists.
First, create your EntLib configuration. In my case, I've got the Data Application Block and Caching Application Block defined/configured. I've also created an alternate config source entity called 'Cache Configuration Source'. It points to another file called separateconfig.config.
Now, the default configuration source is still the System Configuration Source, which is the application's configuration file (application.exe.config). However, I've also created a separate configuration file called separateconfig.config that I want to pull Cache Application Block configuration data from. What I'll do is copy the configuration (including the configSection declaration) from app.config to separateconfig.config for the caching application block:
1: <?xml version="1.0" encoding="utf-8" ?>
4: <section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching, Version=220.127.116.11, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
6: <cachingConfiguration defaultCacheManager="Cache Manager">
8: <add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
9: numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
10: name="Cache Manager" />
13: <add encryptionProviderName="" type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.NullBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=18.104.22.168, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
14: name="Null Storage" />
You can remove this corresponding configuration from the original app.config, although this has implications on configuring this data in the future (more on this later). Now we have to figure out how to pull this configuration when instantiating the CacheManager from the EntLib. The default CacheFactory simply uses the default configuration source (our app.config file) to pull configuration.
1: // native EntLib functionality
2: return CacheFactory.GetCacheManager();
Under the hood, however, what's going on is that the CacheManagerFactory is being passed the default ConfigurationSource and instantiating the CacheManager from that configuration. If we can override the ConfigurationSource being used, then we're golden. Luckily, the lower-level CacheManagerFactory class allows us to do just that. So, we simply create our own implementation of the CacheFactory class and return a singleton, as follows:
1: // only needed if we are overriding the default CacheFactory singleton
2: private static CacheManager cacheManager = null;
3: private static object lockObject = new object();
4: // only needed....
6: private static CacheManager GetCacheManager()
9: // Custom behavior -- use a different config source
10: // In order to provide this, we don't use the default CacheFactory behavior; we create our own.
12: if (cacheManager == null)
14: lock (lockObject)
16: if (cacheManager == null)
18: // Create a custom configuration source
19: IConfigurationSource cacheSource = ConfigurationSourceFactory.Create("Cache Configuration Source");
20: CacheManagerFactory managerFactory = new CacheManagerFactory(cacheSource);
22: cacheManager = managerFactory.CreateDefault();
27: return cacheManager;
As you can see in the code snippet, the Configuration being used to construct a CacheManager is from the "Cache Configuration Source" configuration source that we defined in the system configuration (the app.config). In short, we're pulling from separateconfig.config to construct the CacheManager class.
Pulling this configuration from a separate location has an implication on design-time configuration. Natively, the configuration tool can't persist configuration to different locations at the same time (it simply writes to the default configuration source). I suppose you could investigate modifying the configuration tool to support this functionality, but I haven't explored this myself. I have also seen community-developed tools that will allow you to specify a configuration section and use an alternate ConfigurationSource provider to persist the configuration to an alternate location, but this would always by a manual post-configuration deployment task. In the end, how you achieved this would depend on the effort required to customize the tools or your workflow and the cost associated with the manual effort of persisting the configuration where it ultimately needed to go.