You want to create and add your
own
configuration elements to web.config
. No
predefined element will do, nor will use of the
<appSettings>
key
/value
entries of
web.config
, as described in Recipe 9.2.
Determine what configuration information you want to store in
web.config, create your own
custom section handler for parsing the element, add the definition of
the section handler to web.config
, add the new
configuration element to web.config
, and then
use the configuration information in your application.
Determine what configuration information you want to store in web.config.
Use the .NET language of your choice to create a custom section handler class for parsing your newly defined element.
Add the definition of the section handler to the
<configSections>
section of
web.config
.
Add the new configuration element to web.config
and assign values to its attributes or child elements.
In the code-behind class for your ASP.NET page, use the .NET language of your choice to access and put the custom configuration data to work.
The code we’ve written to illustrate this solution
appears in Example 9-9 through Example 9-14. Example 9-9 (VB) and Example 9-10 (C#) show the class for a custom section
handler. The changes we’ve made to
web.config
to have it use the custom section
handler are shown in Example 9-11. Example 9-12 shows the .aspx
file for
a sample web form that displays some custom configuration settings.
Example 9-13 and Example 9-14 show the code-behind class that accesses the
custom configuration information.
Sometimes the predefined configuration elements provided by ASP.NET,
including the key
/value
collection available through the
<appSettings>
element of
web.config
(described in Recipe 9.2) are not enough. When this is the case, being
able to store any configuration information required by your
application in its own custom section in
web.config
can be a useful alternative.
What’s more, having a custom section in
web.config
can be a real boon to program clarity
and ease of implementation.
As a prelude to discussing the custom section for web.config, it’s worthwhile
reviewing the basic structure of a
machine.config
file, as shown next, because it
is the machine.config file whose
structure we will mimic. The root node of the XML document is
<configuration>
. The
<configSections>
child element is next. It
defines the configuration section elements that will follow and the
configuration handlers (classes
) that will
handle the configuration information contained in the elements. When
<configSections>
is present, it must always
be the first child element of
<configuration>
.
<?xml version="1.0" encoding="UTF-8"?> <configuration> <configSections> .. </configSections> <!-- sections defined in configSections --> </configuration>
Even if you are used to looking at a web.config
file, you have probably never seen the
<configSections>
element. This is because
all of the standard configuration handlers are defined in
machine.config
. (Recall that ASP.NET reads the
machine.config
file first and then the
web.config
file(s) for your application. All of
the data from the machine.config
file is used
unless a section in web.config
overrides the
equivalent section in machine.config
.) Because
<configSections>
is only used to define
configuration handlers, it never appears in a
web.config
file, unless your application uses
custom configuration handlers like the one described in this example.
In this example, we use a <siteProperties>
custom element to hold the information we want to store in
web.config and that will be used
by our custom configuration handler. We have chosen the path of using
a custom element (and a custom configuration handler) because of the
flexibility it affords us and the clarity with which we can express
the information to be stored.
In creating your own custom element, the first thing you need to do
is determine the configuration information you want to store in
web.config
and then define the format that you
want it stored in. The only limitation is that the data element
itself must be a well-formed XML node. You can use attributes, child
elements, or any combination of the two to hold your custom
configuration information. In our example, we use attributes only.
The well-formed XML that defines the section we want to add to our
application web.config
is shown here:
<siteProperties applicationName="ASP.NET Cookbook" databaseServer="10.0.1.12" databaseName="ASPNetCookbook_DB" databaseUserName="aspnetcookbook" databaseUserPassword="efficient" emailServer="[email protected]" />
The section can be named anything you like as long as it does not conflict with any predefined ASP.NET elements. We recommend that, for consistency, you stick with the mixed-case convention used by ASP.NET. Also, be aware that section names and attributes are case sensitive.
After defining your configuration element and specifying the values
of the information it will store, create a custom configuration
handler in a separate project. This way the assembly that is created
can be reused easily in multiple applications. For our example, the
project was named VBCustomConfigHandlers
(CSCustomConfigHandlers
for C#), which by
default will generate an assembly with the same name.
In your configuration handler project, add
a new class named to
reflect the configuration element the handler supports. In our
example, we’ve named the class
VBSiteConfigHandler
(CSSiteConfigHandler
for C#), because the section
added to web.config
contains site configuration
information.
To act as a custom configuration handler, the class
must implement the
IConfigurationSectionHandler
interface:
Namespace VBCustomConfigHandlersPublic Class VBSiteConfigHandler
Implements IConfigurationSectionHandler
.. End Class 'VBSiteConfigHandler End Namespace 'VBCustomConfigHandlers namespace CSCustomConfigHandlers {public class CSSiteConfigHandler : IConfigurationSectionHandler
{ .. } // CSSiteConfigHandler } // CSCustomConfigHandlers
The IConfigurationSectionHandler
interface
requires that you implement a single method,
Create
, which requires three parameters:
parent
, configContext
, and
section
. The parent
parameter
provides a reference to the corresponding parent configuration
section, and the configContext
parameter provides
a reference to the current ASP.NET context. Neither is used in this
example. The section
parameter provides a
reference to the XML node (section) of the
web.config
file that is to be processed. In our
example, section
will be set to reference the
<siteProperties>
section added to
web.config
.
Namespace VBCustomConfigHandlers Public Class VBSiteConfigHandler Implements IConfigurationSectionHandlerPublic Function Create(ByVal parent As Object, _
ByVal configContext As Object, _
ByVal section As XmlNode) As Object _
Implements IConfigurationSectionHandler.Create
..
End Function 'Create
End Class 'VBSiteConfigHandler End Namespace 'VBCustomConfigHandlers namespace CSCustomConfigHandlers { public class CSSiteConfigHandler : IConfigurationSectionHandler {public Object Create(Object parent,
Object configContext,
XmlNode section)
{
..
} // Create
} // CSSiteConfigHandler } // CSCustomConfigHandlers
The Create
method returns an object that contains
the configuration information from the passed section. This can be
anything you want it to be. The most flexible approach is to define a
class that will contain the data and provide easy access by your
application. In our example, the class that will be returned is
defined in the same file as
the
VBSiteConfigHandler
(CSSiteConfigHandler
for C#) class.
Namespace VBCustomConfigHandlers Public Class VBSiteConfigHandler Implements IConfigurationSectionHandler Public Function Create(ByVal parent As Object, _ ByVal configContext As Object, _ ByVal section As XmlNode) As Object _ Implements IConfigurationSectionHandler.Create .. End Function 'Create End Class 'VBSiteConfigHandler'The following class provides the container returned by
'the VBSiteConfigHandler
Public Class VBSiteConfiguration
..
End Class 'VBSiteConfiguration
End Namespace 'VBCustomConfigHandlers namespace CSCustomConfigHandlers { public class CSSiteConfigHandler : IConfigurationSectionHandler { public Object Create(Object parent, Object configContext, XmlNode section) { .. } // Create } // CSSiteConfigHandler// The following class provides the container returned by
// the CSSiteConfigHandler
public class CSSiteConfiguration
{
..
} // CSSiteConfiguration
} // CSCustomConfigHandlers
The VBSiteConfiguration
(CSSiteConfiguration
for C#) class needs a
constructor that has parameters for each
of
the configuration items and a read-only property for each of the
configuration items. The code for our example is shown in Example 9-9 (VB) and Example 9-10 (C#).
After the class that will be used for the return is defined, the
Create
method should extract the configuration
information from the passed XML section, create a new instance of the
VBSiteConfiguration
(CSSiteConfiguration
for C#) object, and then
return a reference to the new instance. For our example, attributes
were used for the configuration information in the section. This
allows us to get a reference to the attributes collection of the
section, and then extract the individual values by using the
GetNameItem
method of the attributes collection.
Public Function Create(ByVal parent As Object, _ ByVal configContext As Object, _ ByVal section As XmlNode) As Object _ Implements IConfigurationSectionHandler.Create Dim siteConfig As VBSiteConfiguration Dim attributes As XmlAttributeCollectionattributes = section.Attributes
With attributes
siteConfig = _
New VBSiteConfiguration(.GetNamedItem("applicationName").Value, _
.GetNamedItem("databaseServer").Value, _
.GetNamedItem("databaseName").Value, _
.GetNamedItem("databaseUserName").Value, _
.GetNamedItem("databaseUserPassword").Value, _
.GetNamedItem("emailServer").Value)
End With 'attributes
Return (siteConfig)
End Function 'Create public Object Create(Object parent, Object configContext, XmlNode section) { CSSiteConfiguration siteConfig = null; XmlAttributeCollection attributes = null;attributes = section.Attributes;
siteConfig =
new CSSiteConfiguration(attributes.GetNamedItem("applicationName").Value,
attributes.GetNamedItem("databaseServer").Value,
attributes.GetNamedItem("databaseName").Value,
attributes.GetNamedItem("databaseUserName").Value,
attributes.GetNamedItem("databaseUserPassword").Value,
attributes.GetNamedItem("emailServer").Value);
return (siteConfig);
} // Create
With the custom configuration handler in hand, you then need to add
the handler information to web.config
to tell
ASP.NET how to handle the <siteProperties>
section you’ve added. Add a
<configSections>
element at the top of your
web.config
that contains a single
section
element. The name
attribute defines the name of the custom section containing your
configuration information. The type
attribute
defines the class and assembly name in the form
type=
"class
,
assembly
" that will
process your custom configuration section. The
class
name must be a fully qualified class
name. The assembly
name must be the name
of the assembly (dll
) created in your
configuration handler project, described earlier.
<configSections> <section name="siteProperties" type="VBCustomConfigHandlers.VBSiteConfigHandler, VBCustomConfigHandlers" /> </configSections>
When the <configSections>
element is
present, it must always be the first element in the
web.config
file after the
<configuration>
element or a parsing
exception will be thrown.
The last thing you need to do before you can use the custom
configuration in your application is to add a reference to the
VBCustomConfigHandlers
(CSCustomConfigHandlers
for C#) assembly in your
application.
Accessing the custom configuration information in your application
requires using ConfigurationSettings.GetConfig
and
passing it the name of your custom
section. This method returns an object that must be cast to the
object type you returned in your custom configuration handler class.
After the reference is obtained, all of the site information is
available simply as properties of the object.
Dim siteConfig As VBCustomConfigHandlers.VBSiteConfiguration siteConfig = CType(ConfigurationSettings.GetConfig("siteProperties"), _ VBCustomConfigHandlers.VBSiteConfiguration) labApplicationName.Text = siteConfig.applicationName labDBServer.Text = siteConfig.databaseServer labDBName.Text = siteConfig.databaseName labDBUserName.Text = siteConfig.databaseUserName labDBUserPassword.Text = siteConfig.databaseUserPassword labEmailServer.Text = siteConfig.emailServer CSCustomConfigHandlers.CSSiteConfiguration siteConfig = null; siteConfig = (CSCustomConfigHandlers.CSSiteConfiguration) (ConfigurationSettings.GetConfig("siteProperties")); labApplicationName.Text = siteConfig.applicationName; labDBServer.Text = siteConfig.databaseServer; labDBName.Text = siteConfig.databaseName; labDBUserName.Text = siteConfig.databaseUserName; labDBUserPassword.Text = siteConfig.databaseUserPassword; labEmailServer.Text = siteConfig.emailServer;
Example 9-9. Custom section handler class (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: VBSiteConfigHandler.vb ' ' Description: This class provides a custom site configuration handler. ' '***************************************************************************** Imports System.Configuration Imports System.Xml Namespace VBCustomConfigHandlersPublic Class VBSiteConfigHandler
Implements IConfigurationSectionHandler
'*************************************************************************
'
' ROUTINE: Create
'
' DESCRIPTION: This routine provides the creation of the
' VBSiteConfiguration from the passed section of the
' web.config file
'-------------------------------------------------------------------------
Public Function Create(ByVal parent As Object, _
ByVal configContext As Object, _
ByVal section As XmlNode) As Object _
Implements IConfigurationSectionHandler.Create
Dim siteConfig As VBSiteConfiguration
Dim attributes As XmlAttributeCollection
attributes = section.Attributes
With attributes
siteConfig = _
New VBSiteConfiguration(.GetNamedItem("applicationName").Value, _
.GetNamedItem("databaseServer").Value, _
.GetNamedItem("databaseName").Value, _
.GetNamedItem("databaseUserName").Value, _
.GetNamedItem("databaseUserPassword").Value, _
.GetNamedItem("emailServer").Value)
End With 'attributes
Return (siteConfig)
End Function 'Create
End Class 'VBSiteConfigHandler
'The following class provides the container returned by 'the VBSiteConfigHandlerPublic Class VBSiteConfiguration
Private mApplicationName As String
Private mDatabaseServer As String
Private mDatabaseName As String
Private mDatabaseUserName As String
Private mDatabaseUserPassword As String
Private mEmailServer As String
Public ReadOnly Property applicationName( ) As String
Get
Return (mApplicationName)
End Get
End Property 'applicationName
Public ReadOnly Property databaseServer( ) As String
Get
Return (mDatabaseServer)
End Get
End Property 'databaseServer
Public ReadOnly Property databaseName( ) As String
Get
Return (mDatabaseName)
End Get
End Property 'databaseName
Public ReadOnly Property databaseUserName( ) As String
Get
Return (mDatabaseUserName)
End Get
End Property 'databaseUserName
Public ReadOnly Property databaseUserPassword( ) As String
Get
Return (mDatabaseUserPassword)
End Get
End Property 'databaseUserPassword
Public ReadOnly Property emailServer( ) As String
Get
Return (mEmailServer)
End Get
End Property 'emailServer
'*************************************************************************
'
' ROUTINE: New
'
' DESCRIPTION: This constructor creates the object and populates the
' attributes with the passed values
'-------------------------------------------------------------------------
Public Sub New(ByVal applicationName As String, _
ByVal databaseServer As String, _
ByVal databaseName As String, _
ByVal databaseUserName As String, _
ByVal databaseUserPassword As String, _
ByVal emailServer As String)
mApplicationName = applicationName
mDatabaseServer = databaseServer
mDatabaseName = databaseName
mDatabaseUserName = databaseUserName
mDatabaseUserPassword = databaseUserPassword
mEmailServer = emailServer
End Sub 'New
End Class 'VBSiteConfiguration
End Namespace 'VBCustomConfigHandlers
Example 9-10. Custom section handler class (.cs)
//---------------------------------------------------------------------------- // // Module Name: CSCustomConfigHandlers // // Description: This class provides a custom site configuration handler. // //**************************************************************************** using System; using System.Configuration; using System.Xml; namespace CSCustomConfigHandlers {public class CSSiteConfigHandler : IConfigurationSectionHandler
{
//************************************************************************
//
// ROUTINE: Create
//
// DESCRIPTION: This routine provides the creation of the
// CSSiteConfiguration from the passed section of the
// web.config file
//------------------------------------------------------------------------
public Object Create(Object parent,
Object configContext,
XmlNode section)
{
CSSiteConfiguration siteConfig = null;
XmlAttributeCollection attributes = null;
attributes = section.Attributes;
siteConfig =
new CSSiteConfiguration(attributes.GetNamedItem("applicationName").Value,
attributes.GetNamedItem("databaseServer").Value,
attributes.GetNamedItem("databaseName").Value,
attributes.GetNamedItem("databaseUserName").Value,
attributes.GetNamedItem("databaseUserPassword").Value,
attributes.GetNamedItem("emailServer").Value);
return (siteConfig);
} // Create
} // CSSiteConfigHandler
// The following class provides the container returned by // the CSSiteConfigHandlerpublic class CSSiteConfiguration
{
private String mApplicationName = null;
private String mDatabaseServer = null;
private String mDatabaseName = null;
private String mDatabaseUserName = null;
private String mDatabaseUserPassword = null;
private String mEmailServer = null;
public String applicationName
{
get
{
return(mApplicationName);
}
} // applicationName
public String databaseServer
{
get
{
return(mDatabaseServer);
}
} // databaseServer
public String databaseName
{
get
{
return(mDatabaseName);
}
} // databaseName
public String databaseUserName
{
get
{
return(mDatabaseUserName);
}
} // databaseUserName
public String databaseUserPassword
{
get
{
return(mDatabaseUserPassword);
}
} // databaseUserPassword
public String emailServer
{
get
{
return(mEmailServer);
}
} // emailServer
//************************************************************************
//
// ROUTINE: Constructor
//
// DESCRIPTION: This constructor creates the object and populates the
// attributes with the passed values
//------------------------------------------------------------------------
public CSSiteConfiguration(String applicationName,
String databaseServer,
String databaseName,
String databaseUserName,
String databaseUserPassword,
String emailServer)
{
mApplicationName = applicationName;
mDatabaseServer = databaseServer;
mDatabaseName = databaseName;
mDatabaseUserName = databaseUserName;
mDatabaseUserPassword = databaseUserPassword;
mEmailServer = emailServer;
} // CSSiteConfiguration
} // CSSiteConfiguration
} // CSCustomConfigHandlers
Example 9-11. Changes to web.config to use the custom section handler
<?xml version="1.0" encoding="utf-8"?> <configuration> ..<configSections>
<section name="siteProperties"
type="VBCustomConfigHandlers.VBSiteConfigHandler, VBCustomConfigHandlers"
/>
</configSections>
<system.web> .. </system.web> ..<siteProperties applicationName="ASP.NET Cookbook"
databaseServer="10.0.1.12"
databaseName="ASPNetCookbook_DB"
databaseUserName="aspnetcookbook"
databaseUserPassword="efficient"
emailServer="[email protected]" />
</configuration>
Example 9-12. Sample web form using custom configuration data (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH09CustomConfigHandlerVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH09CustomConfigHandlerVB"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Custom Config Handler</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmConfiguration" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> Writing Custom Configuration Handlers (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table width="60%"> <tr> <td align="right" width="50%" class="LabelText"> applicationName = </td> <td width="50%" class="LabelText"> <asp:Label ID="labApplicationName" runat="server" /> </td> </tr> <tr> <td align="right" class="LabelText"> databaseServer = </td> <td class="LabelText"> <asp:Label ID="labDBServer" runat="server" /> </td> </tr> <tr> <td align="right" class="LabelText"> databaseName = </td> <td class="LabelText"> <asp:Label ID="labDBName" runat="server" /> </td> </tr> <tr> <td align="right" class="LabelText"> databaseUserName = </td> <td class="LabelText"> <asp:Label ID="labDBUserName" runat="server" /> </td> </tr> <tr> <td align="right" class="LabelText"> databaseUserPassword = </td> <td class="LabelText"> <asp:Label ID="labDBUserPassword" runat="server" /> </td> </tr> <tr> <td align="right" class="LabelText"> emailServer = </td> <td class="LabelText"> <asp:Label ID="labEmailServer" runat="server" /> </td> </tr> </table> </td> </tr> </table> </form> </body> </html>
Example 9-13. Sample web form using custom configuration data code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH09CustomConfigHandlerVB.aspx.vb ' ' Description: This module provides the code behind for the ' CH09CustomConfigHandlerVB.aspx page ' '***************************************************************************** Imports System.Configuration Namespace ASPNetCookbook.VBExamples Public Class CH09CustomConfigHandlerVB Inherits System.Web.UI.Page 'controls on the form Protected labApplicationName As System.Web.UI.WebControls.Label Protected labDBServer As System.Web.UI.WebControls.Label Protected labDBName As System.Web.UI.WebControls.Label Protected labDBUserName As System.Web.UI.WebControls.Label Protected labDBUserPassword As System.Web.UI.WebControls.Label Protected labEmailServer As System.Web.UI.WebControls.Label '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.LoadDim siteConfig As VBCustomConfigHandlers.VBSiteConfiguration
siteConfig = CType(ConfigurationSettings.GetConfig("siteProperties"), _
VBCustomConfigHandlers.VBSiteConfiguration)
labApplicationName.Text = siteConfig.applicationName
labDBServer.Text = siteConfig.databaseServer
labDBName.Text = siteConfig.databaseName
labDBUserName.Text = siteConfig.databaseUserName
labDBUserPassword.Text = siteConfig.databaseUserPassword
labEmailServer.Text = siteConfig.emailServer
End Sub 'Page_Load End Class 'CH09CustomConfigHandlerVB End Namespace
Example 9-14. Sample web form using custom configuration data code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH09CustomConfigHandlerCS.aspx.cs // // Description: This module provides the code behind for the // CH09CustomConfigHandlerCS.aspx page // //**************************************************************************** using System; using System.Configuration; namespace ASPNetCookbook.CSExamples { public class CH09CustomConfigHandlerCS : System.Web.UI.Page { // controls on the form protected System.Web.UI.WebControls.Label labApplicationName; protected System.Web.UI.WebControls.Label labDBServer; protected System.Web.UI.WebControls.Label labDBName; protected System.Web.UI.WebControls.Label labDBUserName; protected System.Web.UI.WebControls.Label labDBUserPassword; protected System.Web.UI.WebControls.Label labEmailServer; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) {CSCustomConfigHandlers.CSSiteConfiguration siteConfig = null;
siteConfig = (CSCustomConfigHandlers.CSSiteConfiguration)
(ConfigurationSettings.GetConfig("siteProperties"));
labApplicationName.Text = siteConfig.applicationName;
labDBServer.Text = siteConfig.databaseServer;
labDBName.Text = siteConfig.databaseName;
labDBUserName.Text = siteConfig.databaseUserName;
labDBUserPassword.Text = siteConfig.databaseUserPassword;
labEmailServer.Text = siteConfig.emailServer;
} //Page_Load } // CH09CustomConfigHandlerCS }