How to have configuration file for DLL
In cases when I need to make some component independently pluggable, I am defining separate configuration file for that component. That is particular useful if you are not the end user of the component, so you can not rely that appropriate configuration sections would be add to the app.config or web.config file.
Today’s use case would be covering the need for defining a collection of user data stored in a component configuration file and that data should be read during the read time and returned as a collection of concatenated strings. Every user entry would have unique Id and first name but not necessarily the last name entry,
Configuration file definition
Would look like something like this:
Configuration file would contain:
- (L4) Configuration section group called “SomeSectionGroupName” and in that section group
- (L5) Configuration section named: “AuthenticationSection”
- (L10) AuthenticationSection would contain configuration ellement collection “UserCollection”
- (L11, L12,L13) which would group collection of “UserConfigurationElement”
As we can see in line 5 of configuration file, AuthenticationSection is defined by type AuthenticationConfigurationSection located in Pluggin assembly.
The code defined there is very simple and it is based on specialization of the base ConfigurationSection with defining the mappings between the config file xml entities and appropriate CLR types
Code is very simple and it looks like this:
In line 8, we are using ConfigurationProperty attribute to define that “this specific config file section would contain a “UserCollection” XML collection element”
In line 11, we define mapping between that element and UserConfigurationElementCollection type and that is all this configuration section
The configuration element collection implementation is based on inheriting the ConfigurationElementCollection and implementing base abstract methods CreateNewElement() and GetElementKey(ConfigurationElement element)
Code looks something like this:
In line 8, we override the abstract creation member and set it up to return new instance of UserConfigurationElement (which is our specialized configuration element – I will cover it in more detail in a few seconds)
In line 13, we override the get element key method to cast the given element to UserConfigurationElement and return its Id property (which is key attribute)
To enable mapping the configuration element XML definition and the CLR configuration element definition we need to add additional overrides in L18 and L23 which enable .NET to find during run time appropriate configuration element type which is to be mapped to certain config element.
Without those two additional overrides, my little sample would throw an ConfigurationErrorsException:
A first chance exception of type ‘System.Configuration.ConfigurationErrorsException’ occurred in System.Configuration.dll
Additional information: Unrecognized element ‘UserConfigurationElement’.
In L11,L12 and L13 we can see that configuration of this element has three properties Id, Name, surname (except in L13 where surname is missing)
Mapping of this configuration definition to .NET type is been done by inheriting the ConfigurationElement class and defining mapping between the configuration element properties and appropriate class properties with optional defining of additional ttributes
That code could look like this:
In line 5, we can see that our UserConfigurationElement inherits the ConfigurationElement
In line 7, we are decorating property Id with configuration property attribute who defines that:
- the Id property is to be mapped to the “id” (case sensitive) XML element property
- that the id element property contains unique identifier data of the configuration element
- that the id element value is required data so it can not be omitted
In line 14, we have the same configuration property attribute decoration but this time we can an example of totally different naming of the .NET property, so we don’t have to follow chosen XML names if we don’t want because attribute constructor element name value defines the mapping
In line 21, we see the same configuration property attribute decoration but with IsRequired = false value definition which in this case mean that some of the elements could be without surname value
Run-time configuration file content read out
Now when we have configuration file defined and appropriate types defining mapping XML->NET all we have to do is to use them during the run time.
The code loading the authentication section from a given config file looks like this:
In determine local path of the configuration file we used:
- in line 4, we got a pointer to the active assembly
- In line 5, we used GetDirectoryName static method of the Path type for active assembly code base propety value.
Then we passed retrieved directory name to the Uri object constructor
- In line 6, we set the ExeConfigFilename property of the fileMap instance (created in line 3), to a string concatenated from uri.LocalPath and hard coded config file name value (This could be enhanced to be dynamically determined to be like asembly.dll.config)
- That file map instance is then passed as a parameter to OpenMappedExeConfiguration method of the COnfigurationManager type
The code is using the local path of the Uri object constructed based upon active assembly directory name to set the ExeConfigFile name property of the ExeConfigurationFileMap type instance. That instance is then passed as parameter to ConfigurationManager OpenMapperdExeConfiguration method
In Line 9 and 10, we retrieve from opened configuration file section group with SomeSectionGroupName and AuthenticationSection section which we cast then to AuthenticationConfigurationSection
L12, just checks if something went wrong
Now when we have strongly typed reference to configuration section, it’s read out is fairly trivial task:
In line 3, we call previously explained method which returns an instance of AuthenticationConfigurationSection pointing to appropriate configuration file section
In line 3 we iterate through all Users (property defined in AuthenticationConfigurationSection which maps “UserCollection” XML element to UserConfigurationElement collection.
In line 6-8, for each UserConfigurationElement we access its properties Id, FirstName and LastName (which are mapped to appropriate xml configuration element properties), and return the string containing concatenated property values.
To test the functionality, I’ve created simple console application with next code:
1: using System;
2: using System.Collections.Generic;
3: using System.Text;
4: using Pluggin;
6: namespace TestDrive
8: class Program
10: static void Main(string args)
12: IEnumerable users =Builder.GetUsers();
13: foreach (string user in users)
which once started results with:
It is possible and in fact it is very simple to define an “application independent” component configuration file which could allow encapsulating the required default component setting up from the end component user while still allowing configuration level customization
You can download source code from here.
|Share this post :|