Microsoft ASP.NET Coding Strategies with the Microsoft ASP.NET Team (Pro-Developer)
One design philosophy of ASP.NET was to create an architecture that allowed a problem to be solved in two ways. This design philosophy is evident in the configuration system in that you have two options for storing configuration data for your own applications: <appSettings />, which is a special configuration section that allows you to store string name/value pairs for easy access in your application; and the custom configuration section handler, which allows you to author a custom configuration section handler capable of reading and processing your own custom configuration sections.
Using Application Settings
Application settings allow you to store commonly used data such as connection strings within the configuration and to access that data through a simple, easy- to-use API.
Tip | Customers often ask us whether they should store data in web.config or global.asax. We recommend you store the data within the configuration file. Storing settings in files such as global.asax implies code. The configuration file allows you to make simple changes without having to recompile your application. Simply add the settings and update the web.config file on your running server. |
The following code demonstrates storing data in the <appSettings /> section of configuration:
<configuration> <appSettings> <add key="DSN" value="server=.;database=pubs;uid=sa;pwd=00password" /> </appSettings></configuration>
The next code example shows accessing the data from within an ASP.NET page:
<%@ Imports Namespace="System.Data" %><%@ Imports Namespace="System.Data.SqlClient" %><%@ Imports Namespace="System.Configuration" %> <script runat="server">Public Sub Page_Load (sender As Object, e As EventArgs) Dim connectionString As String ’ Fetch the connection string from appSettings connectionString = ConfigurationSettings.AppSettings("DSN") Dim connection As New SqlConnection(connectionString) ’ Additional data access code…End Sub</script>
In the preceding sample, we use the ConfigurationSettings.AppSettings property to request the value of the key DSN and use value this for our constructor of a new SqlConnection class instance. We also had to include this:
<%@ Imports Namespace="System.Configuration” %>
Without it, we would have received compile errors when attempting to use the ConfigurationSettings class.
As you can see, application settings are very powerful, and you can use them to store just about any configuration data you can think of. However, you might want something a little more customized, possibly to support nesting or some other structural organization not supported by the flat <appSettings />. In that case, you’ll want to write a custom configuration section handler.
Custom Configuration Section Handler
The role of the custom configuration section handler is to parse configuration data and populate a class instance in which configuration settings can be accessed programmatically in a type-safe manner. The class instance can be retrieved using the ConfigurationSettings.GetConfig method. For example, if we had a custom configuration section handler named ForumsConfiguration, we could access it through a custom handler. Here is the web.config containing our configuration details:
<configuration> <configSections> <sectionGroup name="forums"> <section name="forums" type="ForumsConfigurationHandler, AspNetForums.Components" /> </sectionGroup> </configSections> <forums> <forums defaultProvider="SqlForumsProvider" defaultLanguage="en-en" > <providers> <add name="SqlForumsProvider" type="AspNetForums.Data.SqlDataProvider, AspNetForums.SqlDataProvider" connectionString="[your connection string]" databaseOwner="dbo" /> </providers> </forums> </forums> </configuration>
This configuration file contains a <sectionGroup> for forums as well as defines a new section named forums. We then see the configuration data for the forums. This is the exact configuration system used by the ASP.NET forums.
Here is sample code (written in Visual Basic .NET) showing how we can use the custom configuration section handler to read the configuration data and then use it in a type-safe manner:
Dim configSettings As ObjectDim forumsConfig As ForumsConfigurationDim language As string ‘ Get configuration settings as an objectconfigSettings = ConfigurationSettings.GetConfig("forums/forums") ‘ Cast to the ForumsConfiguration data typeforumsConfig = CType(configSettings, ForumsConfiguration) ‘ Get the default languagelanguage = forumsConfig.DefaultLanguage
The magic happens through a special mapping in web.config:
<section name="forums" type="AspNetForums.Configuration.ForumsConfigurationHandler, AspNetForums.Components" />
This entry in the <configSections> of the configuration file instructs ASP.NET to load a configuration section handler in the namespace AspNetForums.Configuration with a class name of ForumsConfigurationHandler. The class is found in the AspNetForums.Components assembly.
Here is the source for the ForumsConfigurationHandler class, which is provided in C# because it is the same source used in the ASP.NET Forums. (You can download it from www.asp.net.)
namespace AspNetForums.Configuration { // ************************************************************** /// <summary>Class used to represent the configuration data for /// the ASP.NET Forums</summary> // *************************************************************/ public class ForumConfiguration { Hashtable providers = new Hashtable(); string defaultProvider; string defaultLanguage; public static ForumConfiguration GetConfig() { return (ForumConfiguration) ConfigurationSettings.GetConfig("forums/forums"); } // ********************************************************** /// <summary>Loads the forums configuration /// values. </summary> // *********************************************************/ internal void LoadValuesFromConfigurationXml(XmlNode node) { XmlAttributeCollection attributeCollection = node.Attributes; // Get the default provider defaultProvider = attributeCollection["defaultProvider"].Value; // Get the default language defaultLanguage = attributeCollection["defaultLanguage"].Value; // Read child nodes foreach (XmlNode child in node.ChildNodes) { if (child.Name == "providers") GetProviders(child); } } // ********************************************************** /// <summary>Internal class used to populate the /// available providers. </summary> // *********************************************************/ internal void GetProviders(XmlNode node) { foreach (XmlNode provider in node.ChildNodes) { switch (provider.Name) { case "add" : providers.Add( provider.Attributes["name"].Value, new Provider(provider.Attributes)); break; case "remove" : providers.Remove( provider.Attributes["name"].Value); break; case "clear" : providers.Clear(); break; } } } // Properties public string DefaultLanguage { get { return defaultLanguage; } } public string DefaultProvider { get { return defaultProvider; } } public Hashtable Providers { get { return providers; } } } public class Provider { string name; string providerType; NameValueCollection providerAttributes = new NameValueCollection(); public Provider (XmlAttributeCollection attributes) { // Set the name of the provider name = attributes["name"].Value; // Set the type of the provider providerType = attributes["type"].Value; // Store all the attributes in the attributes bucket foreach (XmlAttribute attribute in attributes) { if((attribute.Name!="name") &&(attribute.Name!="type")) providerAttributes.Add(attribute.Name, attribute.Value); } } public string Name { get { return name; } } public string Type { get { return providerType; } } public NameValueCollection Attributes { get { return providerAttributes; } } } // ************************************************************** /// <summary>Class used by ASP.NET Configuration to load ASP.NET /// Forums configuration. </summary> // *************************************************************/ internal class ForumsConfigurationHandler : IConfigurationSectionHandler { public virtual object Create(Object parent, Object context, XmlNode node) { ForumConfiguration config = new ForumConfiguration(); config.LoadValuesFromConfigurationXml(node); return config; } }}
When a request is made for ConfigurationSettings.GetConfig(“forums/ forums”), either the results are read from cache—if they’ve been requested before—or a request is made to the appropriate configuration section handler. In the previous code example, an instance of the ForumsConfigurationHandler was created and a populated instance of ForumConfiguration returned.
As you can see, the code for ForumConfiguration is simply reading and processing the raw XML from the configuration file and returning a strongly typed class.
Категории