Give your DLL a dedicated config file – level 300

Warning:  the following technique uses a child AppDomain and remoting.  If you don’t understand these concepts, then you don’t have a need for this technique.  If all your code runs in a single AppDomain, then all config keys will have to go in the <process>.config file.  In that scenario, if you need additional configuration, you’ll have to use another persistence medium such as a database or custom Xml file.

With that being said, sometimes it is appropriate to run some code in a dedicated AppDomain and shield it from the rest of the process.  In this case, the entry point will be up to you, and the default config file will also be up to you.  You can run a particular class library inside an AppDomain and give it a dedicated config file.  NUnit uses this technique to allow test assemblies to be configurable by naming your config file FooTestAssembly.dll.config.  In a particular application, I have several “plugin” class libraries, and I need each to have dedicated configuration.  I’d like to use the built-in appSettings because this is the “simplest thing that would work”.  Here is how I go about doing this.  You can also download the complete sample solution at my downloads page.

I’m going to create a simple console app to be the entry point for my application:

    5 namespace ConfigTestHarness
    6 {
    7     class App {
    8         static void Main(string[] args) {
    9             AppDomainSetup ads = new AppDomainSetup();
   10             // Set the new AppDomain’s config file any way you see fit.
   11             ads.ConfigurationFile = “ConfigTestClassLibrary.dll.config”;
   12             AppDomain ad = AppDomain.CreateDomain(“Whatever name I choose to give”, null, ads);
   13             // Create a MarshalByRefObject class in the new appdomain and call it
   14             // First argument is the assembly without the .dll.
   15             // Second argument is the fully-qualified type name.
   16             Foo app = (Foo)ad.CreateInstanceAndUnwrap(“ConfigTestClassLibrary”, “ConfigTestClassLibrary.Foo”);
   18             // Ensure this class can get keys from the primary config file.
   19             Console.WriteLine(“Main program config value: ” + ConfigurationSettings.AppSettings[“consoleKey”]);
   20             // Ensure that class running in separate AppDomain can access dedicated keys.
   21             Console.WriteLine(“Class library value: ” + app.GetConfig());
   23             Console.Write(“Press enter to exit.”);
   24             Console.ReadLine();
   25         }
   26     }
   27 }

Notice how I use one configuration item in the default app.config file for this console app?  Now, here is the code for my simple class library:

    4 namespace ConfigTestClassLibrary
    5 {
    6     public class Foo : MarshalByRefObject
    7     {
    8         public string GetConfig() {
    9             return ConfigurationSettings.AppSettings[“classLibraryKey”];
   10         }
   11     }
   12 }

There is no magic here.  It accesses config settings just like any other code would.  The trick is the context in which this code runs.  This code is running in a new AppDomain I created.  I set the configuration file explicitly to “ConfigTestClassLibrary.dll.config”.  You can use any method you’d like to “discover” what name you would like to use, but this is simple.  Now, when my AppDomain is created, that config file is automatically used.  They are isolated.  My class library code can’t access the default config file of the exe, and the exe can’t access “ConfigTestClassLibrary.dll.config”.  AppDomain completely partitions context.  Memory isn’t shared, static state isn’t shared, and configuration isn’t shared.

Using this method, every application plugin I write can run in its own memory space and own its own configuration.