June 07, 2005
.NET | SevenCamels.Framework.Configuration
Class Overview
As promised, here is a rundown on the classes in the revamped SevenCamels.Framework.Configuration library. You can download the library here. Please note the license files in the download.
The first class in the library is the abstract SectionHandler class which serves as the base class for all the other section handlers. One thing about creating your own section handler is that if the XML in the configuration file is wrong, you can get some cryptic error messages, usually of the null reference kind. It's important to validate the XML on the configuration section you're dealing with and provide some nice helpful error messages for the folks who are writing the configuration files. Doing this manually in the code however through node counting and the like is tedious, and not easy to maintain. A quick and easy way to validate your configuration section is by using an XML schema instead.
That's mostly what the SectionHandler class deals with. It has an abstract property for the XSD (the complete XSD, not a filename) which the concrete classes implement. It takes that XSD and applies it to the configuration section using a standard XmlValidatingReader. If the reader finds any discrepancies, an informative ConfigurationException is thrown. One nice thing about the ConfigurationException class is that if you provide it with the XML node where the error took place, it will translate that into a configuration file line number -- and that makes debugging the configuration file for the end user so much easier.
The next class is the DictionarySectionHandler class. The PluginSectionHandler class (which we'll talk about next) works very similar to the DictionarySectionHandler class in the .NET framework in that it uses add, remove and clear XML elements to add, remove and clear plugins from its dictionary collection. It really makes sense to subclass from the .NET DictionarySectionHandler class and override its methods to handle the more detailed add XML elements (you might want to take a look at the "app.config" file in the Example program to see the kind of add XML elements I'm talking about). Unfortunately the DictionarySectionHandler class doesn't provide enough members to override, so I quickly whipped up my own. There's no real reason to use it over the .NET framework version -- it's mostly there for subclassing.
Finally the meat of the library, the PluginSectionHandler class. By now you should be familiar with how section handlers work and specifically how the DictionarySectionHandler class works. Every time it finds an add XML element, it reads it and adds what it finds to a dictionary collection, which eventually gets returned to the calling code. The PluginSectionHandler class works in exactly the same way -- there's just a bit more to read when an add XML element is found. Rather than read all this configuration information itself, it passes this responsibility along to the PluginInfo class which uses the add XML element to initialise itself. Once the PluginInfo is constructed and no errors are found, the PluginInfo is used to instantiate the actual plugin. The new plugin is then added to the dictionary collection.
That's one of the key differences between how I've implemented the Plugin Pattern and the Provider Pattern. Plugins are always instantiated and returned in a dictionary collection for the calling code to use. Providers are a bit more discretionary in that they only instantiate the actual provider when it's requested. As a result the ProviderSectionHandler (coming up) hangs on to the provider configuration information instead of the instantiated providers themselves. The provider factory does the instantiating later.
The PluginInfo and ConstructorParameter classes are pretty straight forward. They receive an XML element when they're constructed which they read to initialise themselves. The PluginInfo class is mostly interested in its key and type. The key differentiates it from other plugins and the type defines what the plugin is actually going to be when instantiated. Valid type strings can be anything from a simple type name, to a full name, to an assembly qualified name. If you're sure the assembly is already loaded before the application reads this configuration information, I'd recommend at least a type full name, otherwise bung in the name of the assembly as well. If there's multiple versions of the same assembly floating around, go for the assembly qualified name instead. Here are some examples:
- Type.Name
ExampleClass - Type.FullName
XYZ.Example.ExampleClass - Type.FullName w/ Assembly Name
XYZ.Example.ExampleClass, XYZ.Example - Type.AssemblyQualifiedName
XYZ.Example.ExampleClass, XYZ.Example, Version=1.0.1983.25223, Culture=neutral, PublicKeyToken=null
The add XML element can contain zero or more constructor parameter XML elements representing the parameters for one of the plugin type's public constructors. The PluginInfo class passes the responsibility of reading these XML elements along to the ConstructorInfo class. The ConstructorInfo class is interested in the name (which isn't really used, it's more for the user), the type and the inner text representing the string value of the parameter. The constructor parameter type can really be anything as long as it has a TypeConverter that can handle conversion from strings. Note, the number and type of constructor parameters must match the signature of one of the plugin type's public constructors.
Finally, the ProviderSectionHandler class. There isn't a lot of difference between this class and the PluginSectionHandler class for the reasons I've described above. Just one method is overriden -- and that is to store the provider configuration information (a PluginInfo) in the dictionary collection instead of the instantiated provider itself.
Posted by Adam Boddington at 02:43 PM | Comments (0)


Post a comment