How to use a ConfigurationElementCollection with custom attributes

The other day I was working on a utility class that did xslt transformations and I wanted to make it read some file paths from the app/web.config file.  I found some great examples on the web about using custom configuration sections for .Net 2.0 (just seach google for “custom config sections”) but then I hit a road block when I wanted my config section to look like this:

<XSLTTransformDefinitions>    <– Inherits ConfigurationSection
<TransformGroups>       <– Inherits ConfigurationElementCollection
<TransformGroup GroupName=”Foo”>    <– Inherits ConfigurationElementCollection

<Transforms>
<Transform Name=”Foo1″ FilePath=”aklsdjf”/>  <– Inherits ConfigurationElement
<Transform Name=”Foo2″ FilePath=”asdfjalsd;fj”/>
<Transform Name=”Foo3″ FilePath=”alsjfajklsd”/>
</Transforms>
<Transforms GroupName=”Bar”>
<Transform Name=”Bar1″ FilePath=”aklsdjf”/>
<Transform Name=”Bar2″ FilePath=”asdfjalsd;fj”/>
</Transforms>

</TransformGroup>
</TransformGroups>
</XSLTTransformDefinitions>

Everything was going great until i realized that I needed to have two layers of collections, I needed my first collection (TransformGroup) to have an attribute that I could use as an identification key later on in the code.  No matter what I did I could not get the configuration manager to read the custom attribute on the “TransformGroup” configurationelementcollection.  When you want a property read by the configuration manager during the GetSection call you are suppose to just add the “ConfigurationProperty” attribute to your property statement in your class like so:

<ConfigurationProperty("Name", IsKey:=True, isrequired:=True)> _
Public Property Name() As String
         Get
                Return DirectCast(Me("Name"), String)
         End Get
         Set(ByVal value As String)
                Me("Name") = value
         End Set
End Property

This works fine when you inherit from the configurationelement and you get access to the base collection via the Me(“SomeAttributeName”) statements  but when you try the same thing in a class that inherits from configurationelementcollection you get an error because the base collection contains in this case “Transform” elements, not attributes read from the element.  After some time of searching and a little bit of trial and error I figured out a hack.  What you have to do is use the “OnDeserializeUnrecognizedAttribute” method.  You can override this method in you class and when the configuration manager finds any attributes on your xml that are not defined by a class somewhere it calls this method allowing you to do something with what it found.  For my solution I just created a property on my “TransformGroup” class called group name and did not add any code attributes to it, then I overrided the method like this:

Protected Overrides Function OnDeserializeUnrecognizedAttribute(ByVal name As String, ByVal value As String) As Boolean 
        If (name = "GroupName") Then 
               Me._GroupName = value 
               Return True 
        End If 
        Return MyBase.OnDeserializeUnrecognizedAttribute(name, value) 
End Function

It is a bit of a hack but it works.  All you have to do is return true from this function, otherwise .Net will throw an exception.

Leave a Reply

Your email address will not be published. Required fields are marked *