I have been looking at the configuration for TexMex, so the XmlSerializerSectionHandler came back to mind. Shortly after I posted my original mod to Craig Andera's XmlSerializerSectionHandler, I made a minor tweak to it to allow the configuration data to be stored in a file external (and relative) to the config file itself. I hadn't posted the diff, but you might find it useful, so it follows here. The discovery bit for me was the [it seems, somewhat oddly-placed]
ConfigurationException.GetXmlNodeFilename(sectionNode);
This allows you to get the FileName from the underlying, undocumented IConfigXmlNode (RIYF). Here is how the configuration file looks, and the contents of the referenced file looks just like it did in the older version:
<configuration>
<configSections>
<section name='NodeConfiguration' type='Improving.Configuration.XmlSerializerSectionHandler, Improving.Utilities' />
<section name='TestData' type='Improving.Configuration.XmlSerializerSectionHandler, Improving.Utilities'/>
</configSections>
<NodeConfiguration file='test.config'/>
<TestData file="TestData\Tests.xml"/>
...
</configuration>
using System; using System.Configuration; using System.IO; using System.Text; using System.Xml; using System.Xml.Serialization; using System.Xml.XPath; namespace Improving.Configuration { public class XmlSerializerSectionHandler : IConfigurationSectionHandler { public XmlSerializerSectionHandler() { } public static string QualifyPath(XmlNode sectionNode, string file) { if(Path.IsPathRooted(file)) { return file; } string configPath=ConfigurationException.GetXmlNodeFilename(sectionNode); string path = Path.GetDirectoryName(configPath); return Path.Combine(path, file); } public XmlNode LoadFile(string fileName) { try { XmlDocument document = new XmlDocument(); document.Load(fileName); return document.DocumentElement; } catch(Exception e) { throw new Exception("Unable to load configuration from file " + fileName, e); } } public object Create( object parent, object configContext, System.Xml.XmlNode section) { if(section == null) throw new Exception("Could not configure section because the node was null"); XmlNode sectionNode = section; if(section.Attributes["file"] != null) { sectionNode = LoadFile(QualifyPath(section, section.Attributes["file"].Value)); } return CreateFromSection(sectionNode); } public object CreateFromSection(XmlNode section) { string typename = section.Attributes["type"].Value; if(typename == null) throw new Exception("You must specify a type name for the configuration to load"); Type t = Type.GetType ( typename, true ); XmlNodeList list = section.SelectNodes("./IncludedTypes/Type/text()"); XmlNode configNode = section.SelectSingleNode("child::*[not(local-name() = 'IncludedTypes')]"); Type[] types = new Type[list.Count]; for(int i = 0; i < list.Count; i++) { types[i] = Type.GetType(list[i].Value, true); } XmlSerializer ser = new XmlSerializer (t, new XmlAttributeOverrides(), types, new XmlRootAttribute(configNode.LocalName), null); return ser.Deserialize(new XmlNodeReader(configNode)); } } }
* Reflector is your friend
Recent Comments