The ConnectionItemElement Class
This class represents each of the
<add> child elements within the parent
<ConnectionItems> element. It exposes the two attributes of each element as the properties named
ConnectionType and
Price. You can see in the following code that both the
connectionType and the price attributes are required for each element, although omitting
IsRequired=true from the
[ConfigurationProperty] attributes would have the same effect:
// maps to and exposes each <add> element
public class ConnectionItemElement : ConfigurationElement
{
[ConfigurationProperty("connectionType", IsRequired = true)]
// returns the value of the "connectionType" attribute
public String ConnectionType
{
get
{
return this["connectionType"].ToString();
}
}
[ConfigurationProperty("price", IsRequired = true,
DefaultValue=(Int32)10), IntegerValidator(MinValue=1,
MaxValue=25)]
// returns the value of the "price" attribute
public Int32 Price
{
get
{
return (Int32)this["price"];
}
}
}
Using Configuration Validators
Notice in the preceding code that the
Price property defines a validator for the corresponding price attribute. This powerful feature lets you apply even finer control over the acceptable values for your custom configuration sections. The example uses an IntegerValidator to specify that the value of the attribute must be between 1 and 25 inclusive using:
[ConfigurationProperty("price", IsRequired = true,
DefaultValue=(Int32)10), IntegerValidator(MinValue=1,
MaxValue=25)]
Notice that the
[ConfigurationProperty] attribute specifies a
DefaultValue in this case, even thoughbecause the attribute is requiredthe default value is never actually used. This is necessary because the configuration system will create an instance of the type specified for the
DefaultValue (in this case an integer) before applying the validator. If you omit the
DefaultValue attribute, and the value to validate is not a String, the validator will report an error.
The DefaultUserElement Class
The final class in the custom configuration handler is the class named DefaultUserElement that exposes the contents of the
<defaultUser> element. This element is a child of the root
<Connections> element. The ConnectionSettingsSection class you saw earlier exposes this element through its
DefaultUser property.
The DefaultUserElement class exposes the values of the two attributes of this element,
userName and
location, as the two properties
DefaultUserName and
DefaultUserLocation. The
location attribute is optional:
// maps to and exposes the values of the <defaultUser>
// element
public class DefaultUserElement : ConfigurationElement
{
// returns the value of the "userName" attribute
[ConfigurationProperty("userName")]
public String DefaultUserName
{
get
{
return this["userName"].ToString();
}
}
// returns the value of the optional "location" attribute
[ConfigurationProperty("location", IsRequired = false)]
public String DefaultUserLocation
{
get
{
return this["location"].ToString();
}
 | |
Figure 1. Relationships: The figure shows the relationships between the custom configuration section and the corresponding configuration handler classes. |
}
}
This combination of classes provides a hierarchical view of the custom configuration section, checks for the presence of required elements and attributes, substitutes default values for optional attributes, and validates the values of the
price attributes. If any required element or attribute is missing, or a
price attribute has an out-of-range value, the .NET configuration system will automatically raise an exception when the application attempts to load the configuration data.
Figure 1 shows the relationship between the configuration section and the classes in the custom handler you have just seen. From this, you can see how you can easily build custom configuration systems for your own applications.