disclaimer This posting is provided "AS IS" with no warranties, and confers no rights.
In my last blog entry, I got a couple of requests for getting “strongly typed” accessors for config. Since the blog format lets me take a meandering walk through configuration, I’ll address things you should do to make your ConfigurationSection-derived class easier to use. First, let me hit some background information because it looks like y’all want some context.
In v1.0 and 1.1, there was only one view of configuration: run-time. That view is implemented by an object call System.Configuration.ConfigurationSettings. ConfigurationSettings returns configuration sections through calls to a static method named GetConfig(string sectionName). The sectionName you passed into GetConfig checks to see that the sectionName itself is valid before any config files are opened. The list of valid sectionName strings can be discovered by looking at the configuration section named configSettings. configSettings itself can contain two types of elements:
Let’s take a look at a hypothetical configuration file:
Given this set of settings, the following strings can be passed into ConfigurationSettings.GetConfig() and the caller has reason to believe that a value should be returned:
What happens here is that the configuration system will take any of these strings and attempt to return a valid object. In v1.0 and v1.1, you will find that most of the objects returned by this call are only understand by the consumers of the configuration. Producers of the configuration (the folks that write the XML) have little hope of being able to make sense of most of the objects that are returned by calls to ConfigurationSettings.GetConfig(). ConfigurationSettings.GetConfig() returns something of type object. Unless you know what type of object to cast to, you have little hope of making sense of the object. In v1.0 and 1.1, that consumer was a runtime thing. The consumer knows what to cast the object to and how to use it.
ConfigurationSettings.GetConfig() looks for xml based on the path passed in via the sectionName argument. In a typical EXE, this search occurs in two files:
For a web application, the search happens in two or more files:
Web applications have another interesting wrinkle called location tags. You can find some information about location tags here. A full discussion on this topic is out of scope for this blog entry.
As each of these files is read, the XmlNode at the particular sectionPath location is searched for. When that XmlNode is located, the XmlNode is handed off to the type identified in the section tag for further parsing and validation. Example:
Machine.config has this XML:
someString="Hello, World!" someBool="false"/>
MyApp.Exe.Config has this XML:
<sectionOne someString="Hello, Application!"/>
The code that consumes the sectionOne section will see the following set of values, assuming that the type picked as a handler merges the sectionOne values in a “typical” fashion:
This particular mechanism works just fine for applications consuming the XML. For folks that need to automate the updates to configuration, only one option really existed: load the configuration files into XmlDocument and make your edits against that document. Everyone else edited by hand. Frankly, it’s pretty hard to remember everything that can possibly be set in a particular sectionGroup or section.
Other fun facts about ConfigurationSettings:
In Whidbey, a new set of objects was added to System.Configuration. What follows is a list that is exhaustive enough for this discussion:
The Configuration object has the following static methods to load configuration in read/write mode:
Each of these three calls returns a Configuration instance. These instances do not share a cache. Each Configuration instance reads configuration independent of the others. These instances stand alone. These instances DO represent the merged view of config (machine.configàapp.config or machine.configàweb.configàweb.config…àweb.config).(Sorry for belaboring the point, but I’ve seen much confusion when I fail to belabor this particular point.) The Configuration instance has two properties that you will be interested in:
SectionGroup has two identical properties. Both of these collections have array indexes with string and integer arguments that return objects. Authors of the sections and sectionGroups are expected to provide a static function that takes a Configuration instance and returns a strongly typed instance of the section or sectionGroup. This is only suggested for sections or sectionGroups that are child elements of the <configuration> element. Example:
public class SectionOne : ConfigurationSection
static public SectionOne(Configuration config)
// Getters and setters for properties omitted
As the user gets the various sections, changes values, and so on, the underlying code tracks those changes and figures out what it needs to write to the active file. These edits can include the following things:
The only file that Configuration will ever write to is the file specified by the call to the static Configuration.GetXXX method. Eventually, the user will call the instance method Configuration.Update(). At this point, the changes to configuration are written out. These changes will not be visible to the consumer of configuration until an AppDomain that has never asked for the settings before is created and makes the request.
ConfigurationSettings is used by the end-consumers of configuration to get configuration from the AppDomain-wide cache. Configuration is used by administrators, setup code, and configuration editors to read and write config for applications and the machine. When you use the Configuration class, you can expect that the type returned by calling Configuration::Sections or Configuration::SectionGroups is the same as the type indicated in the configuration file.
Exception: The type will not be the same if the type does not inherit from ConfigurationSection and instead implements IConfigurationSectionHandler.
When you call ConfigurationSettings.GetConfig(), you may get back the same type as defined in the configuration file. This is not a guarantee. ConfigurationSection contains a virtual function named GetRuntimeObject(). GetRuntimeObject() allows the author of the ConfigurationSection to store a different representation of the data for consumption by the code that uses the particular set of configuration settings to set behavior or do work.
This entry is a summary of what exists in configuration. It attempts to delineate the differences between the runtime configuration class, ConfigurationSettings, and the administrative time class, Configuration. There are a lot of interesting things to talk about with respect to configuring applications using the new classes. This is just a foundation for those future entries.
By the way, if you are reading this and are wondering what has happened to any perceived eloquence or good writing that I maybe used to show in my MSDN writings, I have an explanation. I’ve typically worked with good editors at MSDN, Addison Wesley, and Prentice Hall. Here, I’m performing without a net. I’ll gladly fix areas that are poorly worded though J