The appSettings
element is actually a special case of the general mechanism for
adding custom configuration elements, called the
configuration section. A configuration section
is simply an element in a configuration file. The
ConfigSettings
class knows how to read an
arbitrary configuration section because you add a
configSection
element to the configuration file to
tell it how. The appSettings
configuration section
is defined in the machine configuration file, as shown below:
<section name="appSettings" type="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
I’ll explain more about
the section
element in a moment. You can see,
though, that the section
element shows us that the
appSettings
section is handled by the
System.Configuration.NameValueFileSectionHandler
type. This type’s Create( )
method reads the XML that is passed to it as an
XmlNode
, and creates the
System.Collections.Specialized.NameValueCollection
that is eventually returned by the
ConfigSettings.AppSettings
property.
The steps to create your own custom configuration sections are as follows:
Select a configuration section handler to
handle the configuration section. If none of the built-in
configuration section handlers are appropriate, write your own class
that implements IConfigurationSectionHandler
.
Add a section
element
to the configSections
element of the machine or
application configuration file, which links the section name to the
type of the class you created in step 1.
Add the configuration section defined in step 2 to the machine or application configuration file.
Write the code to access the configuration settings using the
ConfigSettings.GetConfig( )
method.
The
IConfigurationSectionHandler
interface requires
only one method, Create( )
, which returns an object
containing the configuration section’s settings in a
useful form. This object will be returned by
ConfigurationSettings.GetConfig( )
. The .NET
Framework includes five built-in configuration section handlers,
which are listed below:
DictionarySectionHandler
Create( )
will return a Hashtable
containing the key-value pairs of the configuration section
element’s child add
elements. The
configuration section may also contain remove
and
clear
child elements. Because the
Hashtable
is more efficient for large numbers of
key-value pairs, this handler should be reserved for use with a large
number of configuration settings.
IgnoreSectionHandler
Used to indicate that the configuration
system class should ignore this configuration section. The
IgnoreSectionHandler.Create( )
method always
returns null
. This handler is typically used
internally by the .NET Framework, although you can use it if you
wish.
NameValueSectionHandler
Behaves
similarly to DictionarySectionHandler
, except that
Create( )
returns a
NameValueCollection
rather than a
Hashtable
. This handler is better suited for
configuration sections with fewer than ten settings.
NameValueFileSectionHandler
Behaves similarly to NameValueSectionHandler
,
except that it also allows the element to have a
file
attribute, which specifies an additional XML
file to read for configuration settings. The external
file’s root element name must be the same as the
current element. This is the handler used for
appSettings
configuration sections, as shown in
Examples 15-1 and 15-2.
SingleTagSectionHandler
Create( )
will return a Hashtable
containing key-value pairs of the element’s
attribute names and values. The element may not have any child nodes.
You should use this handler if you configuration section will consist
of a single element with one or more attributes.
For some purposes, none of the built-in
configuration section handlers may be appropriate. In that case, you
can write your own handler by implementing
IConfigurationSectionHandler
. This interface has
only method to implement, Create( )
. One of
Create( )
’s parameters is the
XmlNode
containing the configuration section
element itself.
Perhaps the simplest custom section handler would just return the XML
used to construct the configuration section. Example 15-4 shows an implementation of
XmlSectionHandler
that does that.
using System; using System.Configuration; using System.Xml; public class XmlSectionHandler : IConfigurationSectionHandler { public object Create(object parent, object configContext, XmlNode section) { return section; } }
If
you use this XmlSectionHandler
,
you’ll see that the Create( )
returns an instance of
System.Configuration.XmlConfigElement
, which is an
undocumented subclass of XmlElement
. You
shouldn’t care what concrete type it is, as long as
you treat it as an XmlElement
.
Once you’ve selected or
written a configuration section handler, you need to define the
configuration section and tell the configuration system of how to
deal with it. To do this, you add a section
element to the configuration file’s
configSections
element.
The section
elements
define how a configuration section is to be handled. The
section
element has two attributes,
name
and type
. The
name
attribute matches the name of a configuration
section element that appears in a configuration file, and the
type
attribute specifies the name of the
IConfigurationSectionHandler
instance that will
handle the configuration section.
section
elements may be organized into a
hierarchy using section groups. The element that defines section
groups is called, appropriately, sectionGroup
, and
its only attribute is name
. You can nest as many
sectionGroup
elements as you want, and a
sectionGroup
may contain both
section
elements and other
sectionGroup
elements.
Example 15-5 shows the
configSections
element of an application
configuration file using the XmlSectionHandler
in
a configuration section group.
<configSections> <sectionGroup name="Group"> <section name="Custom" type="XmlSectionHandler, AppSettingsTest" /> </sectionGroup> </configSections>
The type
attribute contains the full class name of
the configuration section handler in standard .NET style: class name,
assembly name, version, culture, and public token key. You can omit
the version, culture, and public key token if the assembly is not in
the global assembly cache. In this case,
XmlSectionHandler
is contained in the same
assembly as the AppSettingsTest
executable.
The next
step is to add the configuration section itself to the configuration
file. Because of the way I wrote the
XmlSectionHandler
, it will accept any XML content.
The only restriction on how it’s used in the
configuration file is that it must appear in the section group as
defined in Example 15-5. Example 15-6
shows the complete application configuration file containing the
configSections
element, the
Custom
element I defined in the
configSections
element, and the
appSettings
element from Example 15-2.
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <configSections> <sectionGroup name="Group"> <section name="Custom" type="XmlSectionHandler, AppSettingsTest" /> </sectionGroup> </configSections> <appSettings> <remove key="some key" /> <add key="some other key" value="some other value" /> <add key="some numeric key" value="5.00987" /> </appSettings> <Group> <Custom> <someElement attribute="attribute1">some content & stuff <![CDATA[Some <text> that the parser won't even try to parse ]]> </someElement> </Custom> </Group> </configuration>
Remember that you don’t need to add a
section
element for the
appSettings
configuration section in your
application configuration file because it’s already
included in the machine configuration file. Also, be sure to note
that, although I’ve put it in the application
configuration file, all of this configuration could also go in the
machine configuration file.
Now you’re ready to
actually use the configuration data in the application configuration
file. You already know how to access configuration settings in the
appSettings
section using
ConfigurationSetting.AppSettings
property. You can
also access them using the ConfigurationSettings.GetConfig(
)
method. The only parameter to GetConfig(
)
is a string
containing the path to the
configuration section you want to get.
In fact, the AppSettings
property is simply a
proxy that calls the GetConfig( )
method, passing
the string “appSettings”.
Example 15-7 shows a program that gets configuration
settings from the appSettings
and
Custom
configuration sections.
using System; using System.Configuration; using System.Xml; public class AppSettingsTest { public static void Main(string [ ] args) { try { string someKey = "some key"; Console.WriteLine("{0}={1}", someKey, ConfigurationSettings.AppSettings[someKey]); string someOtherKey = "some other key"; Console.WriteLine("{0}={1}", someOtherKey, ConfigurationSettings.AppSettings[someOtherKey]); string someNumericKey = "some numeric key"; AppSettingsReader reader = new AppSettingsReader( ); Console.WriteLine("{0}={1}", someNumericKey, reader.GetValue(someNumericKey,typeof(decimal))); Console.WriteLine( ); string custom = "Group/Custom"; XmlNode customConfig = (XmlNode)ConfigurationSettings.GetConfig(custom); Console.WriteLine("{0}={1}", custom, customConfig); Console.WriteLine("{0}={1}", customConfig.Name, customConfig.InnerXml); } catch (Exception e) { Console.Error.WriteLine(e); } } } public class XmlSectionHandler : IConfigurationSectionHandler { public object Create(object parent, object configContext, XmlNode section) { return section; } }
Running this program, you’ll see the following output:
some key= some other key=some other value some numeric key=5.00987 Group/Custom=System.Configuration.ConfigXmlElement Custom=<someElement attribute="attribute1">some content & stuff <![CDATA[Some <text> that the parser won't even try to parse ]]></someElement>
When
calling ConfigurationSettings.GetConfig( )
, you
are responsible for knowing what type of object is being returned by
the configuration section handler. If you cast the returned object to
an incompatible type, an InvalidCastException
will
be thrown.
It’s
particularly important to be aware of return types if you try to use
NameValueSectionHandler
and
DictionarySectionHandler
interchangeably. Although
both handlers will happily read the same XML from the configuration
file, NameValueSectionHandler
returns a
NameValueCollection
, while
DictionarySectionHandler
returns a
Hashtable
.
3.146.255.127