Extending .NET 2.0 Configuration

Damir Dobric Posts

Next talks:

 

    

Follow me on Twitter: #ddobric



 

 

Archives

.NET 2.0 offers very powerful configuration mechanism, which allows you to build you custom configuration sections,
elements etc. Unfortunately, many details are very poor documented. In this post I will shortly show some interesting details.

For example, imagine you want to build your own section, which can be configured as shown below:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
<
configSections>
<
section name="MySection"
type="MyLibrary.MySectionClass,
MySectionAssembly, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null
" />

</configSections>
 …


The shown configuration snippet defines the configuration section "MySection" implemented in the type
MyLibrary.MySectionClass and assembly MySectionAssembly. Additionally, let's say the configuration
should look as shown in the next example:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
<
configSections>
<
section name="MySection" 
         type="MyLibrary.MySectionClass,
         MySectionAssembly, Version=1.0.0.0, Culture=neutral, 
         PublicKeyToken=null
" />

</configSections>

. . .

<MySection>
 <
dynamicEndpoints>
   <
dynamicEndpoint name="MyTestEndpoint1"
                    behaviorConfiguration="SomeBehavior"/>
   <
dynamicEndpoint name="MyTestEndpoint2"
                    behaviorConfiguration="SomeBehavior"/>
 </
dynamicEndpoints>
</
MySection >


The section should contain a property dynamicEndpoints of type list, which contain multiple elements dynamicEndpoint.
The element dynamicEndpoint contains two custom attributes: name and behaviorConfiguration.
Next example shows how to implement this scenario. First that have to be done is to implement the class which is serialized
as section element. In this case MySection.

using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;

namespace MyLibrary
{
    public class MySectionClass : ConfigurationSection
    {
       [ConfigurationProperty("dynamicEndpoints", IsRequired = true)]
       public DynamicEndpointElementCollection DynamicEndpoints
       {
          get
          {   
              return (DynamicEndpointElementCollection)
              
base["dynamicEndpoints"]; 
          }
       }
    }
    
}


This example implements the section class, which has one property of type DynamicEndpointElementCollection.
The interesting thing at this place is attribute IsRequired. This specifies whether the attribute is mandatory or optional one.
In the next step the collection dynamicEndpoints has to be implemented. Next example is all you have to implement.

using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;


namespace MyLibrary
{

[ConfigurationCollection(typeof(DynamicEndpointConfigElement),
AddItemName = "dynamicEndpoint")]
public class DynamicEndpointElementCollection : ConfigurationElementCollection
{
   protected override ConfigurationElement CreateNewElement()
   {
      return new DynamicEndpointConfigElement();
   }

         protected override Object GetElementKey(ConfigurationElement element)
         { 
             
return ((DynamicEndpointConfigElement)element).Name;
        
}
    }
}


It is important to notice the attribute AddItemName. This attribute defines the name of the element as it will
appear in the list. Without of setting of this attribute the configuration would look a little different:

<add name="Uri" behaviorConfiguration=" />

As you see, the element is in this case some kind of untyped configuration element. Such elements are useful for untyped information
like properties which cannot be determined at the time design time.
At the end the element have to be implemented as shown in the next example.

using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;


namespace MyLibrary

{

public class DynamicEndpointConfigElement : ConfigurationElement
{
  [ConfigurationProperty("behaviorConfiguration", IsRequired = true)]
  public string BehaviorConfiguration
  {
     get { return (string)base["behaviorConfiguration"]; }
  
}

  [ConfigurationProperty("name", IsRequired = true)]
  public string Name
  {
     get { return (string)base["name"]; }
  
}
 }
}


An intersting example can be donloaded here.

Posted Feb 07 2007, 10:55 PM by Damir Dobric
Filed under:

Comments

Damir Dobric Posts wrote Reading of WCF configuration
on 02-07-2007 23:32

Sometimes it is required to read the WCF specific information contained in the application's configuration

Ed wrote re: Extending .NET 2.0 Configuration
on 09-03-2007 13:50

Hi, that's interesting for normal configuration sections, but mine isn't normal :D, I have an abstract class called Destination, and 2 derived classes called FileDestination and DbDestination so I can have a Destinations collection and call the abstract WriteEntry method for all Destinations.

Well, I'd like to use a config section similar to:

<LogSettings>

 <Destinations>

   <FileDestination>

     <Filename>filename</Filename>

     <Path>path</Path>

     <Enabled>true</Enabled>

   </FileDestination>

   <DbDestination>

     <ConnectionString>connection string</ConnectionString>

     <TableName>table</TableName>

     <Enabled>true</Enabled>

   </DbDestination>

 </Destinations>

</LogSettings>

Is it possible? how??

Damir Dobric wrote re: Extending .NET 2.0 Configuration
on 09-03-2007 14:46

Hi Ed, you class is the usual one, but a little bit more tricky. The way you want to use class derivation reflected to the configuration is not well object oriented design.

In general, there are two ways to do that:

<LogSettings>

<Destinations>

 <Destination provider=”file” providerSettings=”…”/>

 <Destination provider=”db” providerSettings=”here connection string etc”/>

 <Destination provider=”whatever” providerSettings=”…”/>

<LogSettings>

or

LogSettings

 Destinations

   FileDestination

   DbDestination

   WhatEverDestination

If you use the first one, it is not the typed one. In this case you would work provider specific (similar like ADO.NET). In this case the Destinations element would be a ConfigurationElementCollection. Destination element would be usual ConfigElement.

In the second case the Destinations element is a ConfigElement and all other DestinationXXX should be members of that element.

In boot cases, LogSettings could be a section.

Hope this help.

Ed wrote re: Extending .NET 2.0 Configuration
on 09-03-2007 17:28

Wow, you answered fast :) thanks :)

Yep, it helped :) I had to separate the 2 collections in separate Section properties... then I add manually a property (not ConfigurationProperty) that merges both, so my Logger class still works the same.

Just a little observation, at first it didn't load my values, searching in other sites I saw I still needed another thing to use them, guess you have that also somewhere your program but forgot to write it here:

_settings = (MySection) ConfigurationManager.GetSection("MySection");

Bye :)

Damir Dobric wrote re: Extending .NET 2.0 Configuration
on 10-01-2007 10:44

Here is an example which shows how to read bindings by using of section path:

configuration.GetSection("system.serviceModel/bindings")

Todd Taylor wrote re: Extending .NET 2.0 Configuration
on 02-01-2008 0:19

Thank you, Damir, for posting this article and code sample.   I was totally stuck with trying to create the appropriate classes for a rather complicated configuration file.   Most of the code samples I found online were too basic to help me resolve the issues I was having.  Thanks to your code sample, I was able to get my code working :o)

Todd Taylor wrote re: Extending .NET 2.0 Configuration
on 02-04-2008 21:05

I found-out that you don't need to define the "File" property if you want to use a linked configuration file (as shown in the sample code download).  

Instead, add the attribute "configSource" which is part of the .NET Framework:  

<MyCustomSection configSource="Configuration\MyConfig.config" />

Damir Dobric wrote re: Extending .NET 2.0 Configuration
on 02-05-2008 8:17

This is right Todd. You do not have to. The idea of this example was to show how to do that behind the scene. For example, my requirement was to load the configuration from database or to collect information from several web services, put them together and create the dynamically configuration node.

developers.de is a .Net Community Blog powered by daenet GmbH.