Improving on XmlSerializationSectionHandler
I've been working on extending some of our web.config file usage, and came across an excellent piece of code written by Craig Andera. The idea is to create a section handler (implementing IConfigurationSectionHandler) that makes use of XmlSerialization. You indicate in your configuration section what type to deserialize, and presto-change-o. Ok, so far so good. This approach would relieve you from having to write a new section handler for the more complex types of configuration information.
I ran with this, and I discovered that XmlSerialization requires that you name the element the same as your class. If your names don't match, the XmlSerializer throws an InvalidOperationException. To comply with this, you would have to have a config section that looks like:
18 <TestClass type="Lycos.Configuration.NUnit.TestClass, Lycos.NUnit">
19 <Name>jiggy</Name>
20 </TestClass>
The problem is that instantiating multiple objects is problematic in that presumably, section names should be unique. (Note: this does not appear to be a restriction in .NET configuration, but it seems to me that it's a good idea. If someone knows otherwise, I'd be curious to know).
I don't want to live with this limitation if I don't have to. The name of the section should be completely independent of any implementation details. I decided a good approach would be to nest the deserialized element inside the section.
15 <section name="goodXmlSerializer" type="Stuff.Configuration.XmlSerializerSectionHandler, Stuff"/>
16 </configSections>
17 <emptyXmlSerializer/>
18 <goodXmlSerializer>
19 <TestClass type="Stuff.TestClass, Stuff.NUnit">
20 <Name>jiggy</Name>
21 </TestClass>
22 </goodXmlSerializer>
This required an update to the section handler code:
14 public object Create(object parent, object configContext, XmlNode section)
15 {
16 XPathNavigator nav = section.CreateNavigator ();
17 string typename = ( string ) nav.Evaluate ("string(./*[1]/@type)");
18 if (typename == null || typename.Length == 0) return null;
19 Type t = Type.GetType ( typename );
20 XmlSerializer ser = new XmlSerializer (t);
21 return ser.Deserialize (new XmlNodeReader (section.FirstChild));
22 }
This code grabs the first (and presumably only) child of the section, and uses it as before.
UPDATE: I should've noted that there is another option, which is to set the element name on the class using one of the XML serialization attributes. But this approach still leaves you having one element name per class, rather than one per instance.
_________________
|