Configuration file (App.Config) for .NET Class Library (.dll)

If you ever deploy a .net class library that isn’t being called by a .net application and references items in the config file then you will have to determine where the .net configuration subsystem will look for the config file and what it should be called. In hindsight, the answer seems rather obvious but I spent several hours figuring this out one day. In my case, I was deploying a managed DLL with a thin COM wrapper that would be called by Excel. In order to get this to work, we placed all the DLLs in the same directory as Excel.exe, called REGASM on the generated .tlb file, and named our config file Excel.exe.config.

Like I said, so obvious in hindsight but not the first (or tenth) thing you think of.

Advertisements

Custom ConfigurationSections in .NET 2.0 .config Files

Recently, I was needing to store information about 5 instances of an application server that I was accessing from my program.  As I was entering the third set of values in <appSettings> section I decided to go a better route.  What I wanted seemed simple: a section that worked exactly like the <connectionStrings> section, but with my own attributes.  After several hours with the documentation and some on-line research, I got what I wanted.  I was hoping it would only take 20-30 minutes.  In order to provide you with the experience I hoped to have, I have written this post.

First, let show you what I wanted my section to look like:

<acmeConfiguration>
 <add name="ERCOT"
  connectionName="AcmeER" fileDir="\\server\path" baseUrl="http://server:9999" />
  <add name="PM"
   connectionName="AcmePM" fileDir="\\server2\path" baseUrl="http://serverxx:9901" />
</acmeConfiguration>

You will need to subclass three classes from System.Configuration namespace: ConfigurationSection, ConfigurationElementCollection, and ConfigurationElement which correspond to the <acmeConfiguration>, the set of elements within <acmeConfiguration>, and the <add> elements respectively.  Understanding the above is the key to simplifying this exercise.  Here’s the code that implements the section above:

public class AcmeConfigSection : ConfigurationSection {
[ConfigurationProperty("", IsRequired=true, IsDefaultCollection=true)]
  public AcmeInstanceCollection Instances {
   get { return (AcmeInstanceCollection) this[""]; }
   set { this[""] = value; }
  }
}

public class AcmeInstanceCollection : ConfigurationElementCollection {
  protected override ConfigurationElement CreateNewElement() {
   return new AcmeInstanceElement();
  }
  protected override object GetElementKey(ConfigurationElement element) {
   return ((AcmeInstanceElement) element).Name;
  }
}
public class AcmeInstanceElement : ConfigurationElement {
  [ConfigurationProperty("name", IsKey=true, IsRequired=true)]
  public string Name {
   get { return (string) base["name"]; }
   set { base["name"] = value; }
}

  [ConfigurationProperty("connectionName", IsRequired=true)]
  public string ConnectionName {
   get { return (string)base["connectionName"]; }
   set { base["connectionName"] = value; }
  }

  [ConfigurationProperty("fileDir", IsRequired = true)]
  public string FileDir {
   get { return (string)base["fileDir"]; }
   set { base["fileDir"] = value; }
  }

  [ConfigurationProperty("baseUrl", IsRequired = true)]
  public string BaseUrl {
   get { return (string)base["baseUrl"]; }
   set { base["baseUrl"] = value; }
  }
 }

Finally, for convenience, I created a class to provide static access to this collection similar to System.Configuration.ConfigurationManager.ConnectionStrings:

public class AcmeConfig {
  protected static Dictionary<string, AcmeInstanceElement> _instances;
  static AcmeConfig() {
   _instances = new Dictionary<string,AcmeInstanceElement>();
   AcmeConfigSection sec = (AcmeConfigSection) System.Configuration.ConfigurationManager.GetSection("AcmeConfiguration");
   foreach ( AcmeInstanceElement i in sec.Instances ) {
    _instances.Add(i.Name, i);
   }
  }
  public static AcmeInstanceElement Instances(string instanceName) {
   return _instances[instanceName];
  }

  private AcmeConfig() {
  }

}

That’s it.  I wish MS would put a sample like mine in the docs because I think this is what 99% of developers are looking for.