Configuration

The .NET Framework provides a powerful and flexible means of configuring applications. This configuration is accomplished by using text-based XML configuration files. The machine-wide configuration file is called machine.config (described later). This file is supplemented by application-specific configuration files, also described shortly.

This configuration scheme offers the following advantages:

  • The XML files that control the configuration can be edited with any standard text editor or XML parser. It is not necessary to use special configuration tools, although the .NET Framework does include a graphical configuration tool.
  • Since the configuration is accomplished with text files, it is easy to administer remotely. Files can be created or edited on a development machine, and then copied into place via FTP or remote network access by anyone with security clearance.
  • The system is hierarchical. Each application inherits a baseline configuration from machine.config. The application configuration file then applies successive configuration attributes and parameters.
  • A corollary of the hierarchical nature of the system is that each application can have its own independent configuration. Applications do not need to share a machine-wide configuration.
  • The system is extensible. The baseline system provides configurability to a large number of standard program areas. In addition, you can add custom parameters, attributes, and section handlers, as required by your application.
  • The configuration settings for each application are computed at load time, using all the relevant hierarchical configuration files, if they exist. Changes made to any configuration files after the program begins execution will not take effect until the program is terminated and restarted.

    This last point is distinctly different from the way that ASP.NET web applications are configured. ASP.NET automatically detects whether any configuration files anywhere in the hierarchy are modified, recomputes and re-caches the configuration settings accordingly, and transparently starts a new application domain. For a complete discussion of configuration of ASP.NET applications, see our book Programming ASP.NET (O'Reilly).

22.2.1 Hierarchical Configuration

The configuration system is hierarchicalconfiguration files are applied in successive order. Unlike many hierarchies, and unlike ASP.NET configuration, this hierarchy does not have any parallel branchesonly levels.

A file called machine.config is at the top of the hierarchy. This file is contained in the subdirectory:

c:windowsMicrosoft.NETFrameworkversion numberCONFIG

where version number will be replaced with the version of the .NET runtime installed on your machine, such as v1.1.4322.

The next level in the configuration hierarchy has publisher policy files. These files are provided by the publisher of an assembly and are associated with a specific version of a specific assembly. They apply to all managed applications that call that assembly's version. Their purpose is to redirect requests for older versions of an assembly to the new version. The creation and use of publisher configuration policy files is obscure and beyond the scope of this book (see the integrated documentation from Microsoft for details).

The bottom level of the configuration hierarchy is the application-specific configuration file, named after the application executable with an additional extension of .config, and located in the same directory as the executable file. For example, if an application executable file is called SomeApp.exe, the configuration file associated with that application will be SomeApp.exe.config.

As discussed in Section 22.5, later in this chapter, Visual Studio .NET can build either a Debug or a Release version of an application (or a custom version). If you build a debug or release version in C#, VS.NET will output to a subdirectory of the project called binDebug or binRelease, respectively. (When using VB.NET, both Debug and Release versions of the output go to the bin directory.) Since the application configuration file must be in the same directory as the executable, and with the correct name corresponding to the name of the executable, you must manually create copies of the application configuration file and place one in each output directory.

To avoid this tedious requirement, create a single application configuration file named app.config and place it in the project's root directory. In Solution Explorer, add the file app.config to the project by right-clicking on the project, selecting Add Add New Item, and then selecting Application Configuration File. When the project is built, the configuration file will be correctly renamed automatically and copied to the output directory (such as Debug or Release).

The application configuration files are optional. If there are none for a given application, then the configuration settings contained in machine.config will apply to that application without any modification.

Each application executable can have at most a single configuration file. The configuration settings contained in an application configuration file apply only to that application. If an application configuration file contains a setting that is in conflict with a setting higher up in the configuration hierarchy (i.e., in machine.config), then the lower-level setting will override and apply to its application.

Security Configuration Files

Hierarchical configuration files also apply security policy. At the top of the security hierarchy is an enterprise security policy file, called enterprisesec.config, which applies to all managed code in an enterprise setting. Next in the hierarchy is a file called security.config, which contains the machine-wide security policy. Both files are in the same location as machine.config. Next are configuration files applicable to specific users of the machine, also called security.config, located in:

c:Documents and Settingsuser nameApplication DataMicrosoftCLR Security Configversion number

When an application runs, it uses the intersection of permissions granted in all the security configuration files. Successive configuration files cannot increase the permissions granted at another level, but they can decrease the permissions.

These security configuration policy files are best administered by using the .NET Framework Configuration Tool, described later, or the command-line Code Access Security Policy tool (caspol.exe).

The application configuration files described here don't meet all the configuration requirements an application may have. For example, you cannot store user settings for multiuser applications here because the config files are per application and not per user. In addition, updating a config file as an application runs requires write access to Program Files, which is normally granted only to users with Administrative privileges. If you want to store per-user configuration settings, use some other technique, such as writing a custom XML file or making a Registry entry.

22.2.2 Configuration File Format

The configuration files are XML files. As such, they must be well formed. (For a description of well-formed XML files, see the sidebar Sidebar 22-2.)

Typically, tag and attribute names consist of one or more words using camel case. Attribute values are usually Pascal cased.

Camel casing means that you combine multiple words, with each word except the first capitalized. For example, you might have a tag named myNewTag.

Pascal casing is exactly like camel casing, except the first letter is uppercase as well: MyNewAttribute.

Note that not all attributes use Pascal casing:

  • true and false are always lowercase.
  • Literal strings do not adhere to either camel or Pascal casing for example, a database connection string, may be specified as "SERVER=Zeus;DATABASE=Pubs;UID=sa;PWD=secret;".
  • If the value is the name of another tag in a configuration file, then it will be camel-cased.

    Well Formed XML

    XML files must be well-formed, meaning that they must conform to a very specific set of formatting rules to avoid rejection by the XML parser. The rules of well-formed XML include:

    • Close All Tags. In well-formed XML, there will always be a closing tag, such as . Many tags can be made self-closing by putting the closing forward slash within the tag itself. This makes it well formed. For example:

      />
    • No Overlapping Tags. Well-formed XML requires that tags do not overlap. For example, the tags in the following line of code overlap the tag within the tag:

      This is the yearfor the Red Sox.

      This line can be made well formed by avoiding the overlap:

      This is the yearfor the Red Sox.
    • Case Sensitivity. XML files are case sensitive.
    • Start- and end-tags must have matching cases.
    • All attributes are enclosed in either single or double quotation marks.
    • All XML files must have a single top-level root. The top-level element in a configuration file must be . Remember to close it at the end with .
    • Reserved Characters. The only five built-in character entities in XML are:

      < <
      > >
      & &
      " "
      ' '

    If any of these characters is used in script, then it must be "escaped" by using the character entity above, or by enclosing the entire script block in a CDATA section. (CDATA is an XML type.)

    For more information on well formed XML see XML in a Nutshell by Elliotte Rusty Harold and W. Scott Means (O'Reilly).

The first line in the configuration files declares the file an XML file, with attributes specifying the version of the XML specification to which the file adheres and the character encoding used.

The character encoding specified here is UTF-8, which is a superset of ASCII. The character-encoding parameter may be omitted only if the XML document is written in either UTF-8 or UTF-32. Therefore, if the XML file is written in pure ASCII, the encoding parameter may be omitted, although including the attribute contributes to self-documentation.

This first line is an exception to the rule and does not have a corresponding closing tag.

The next line in the configuration files is the opening tag:


 

The entire contents of the configuration file, except the initial XML declaration, is contained between the opening tag and the closing tag.

Comments can bec contained within the file by using the standard HTML comment:

Comments may be located anywhere within the file except prior to the first line that declares the XML file.

Within the tags are two broad categories of entries. They are, in the order in which they appear in the configuration files:

  • Configuration Section Handler Declarations
  • Configuration Sections

22.2.3 Configuration Section Handler Declarations

The first part of the machine.config file consists of handler declarations that are contained between an opening tag and a closing tag. Each handler declaration specifies the name of a configuration section, contained elsewhere in the file, that provides specific configuration data. Each declaration also contains the name of the .NET class that will process the configuration data in that section.

This terminology can be very confusing. The first part of the file is enclosed in tags, but contains only a list of the configuration sections and their handlers, not the configuration sections themselves. And as you will see shortly, the configuration sections are each contained within tags, but no grouping tag contains all the separate configuration sections, analogous to .

The machine.config file contains, in the default installation, many configuration section handler declarations that cover the areas subject to configuration by default. (Since this system is extensible, you can also create your own, as described next.)

A typical entry containing a handler declaration is shown in Example 22-1.

In the original machine.config file, the contents of Example 22-1 were all contained in a single line. That line is broken here only for readability.

 

Example 22-1. A typical configuration section handler declaration


 

Despite appearances to the contrary, this

tag has only two attributes: name and type. The name is system.diagnostics. This name implies that somewhere else in the configuration file lies a configuration section called system.diagnostics. That configuration section contains the actual configuration settings, which typically are name/value pairs contained within XML elements, to be used by the application(s). It will be described in detail shortly.

The type attribute has a lengthy value enclosed in quotation marks. It contains:

  • The class that handles the named configuration section
  • The assembly file (DLL) that contains that class
  • Version and culture information to coordinate with the assembly file
  • A public key token used to verify that the DLL being called is secure

Each handler need only be declared once, either in the base-level machine.config file or in an application configuration file further down the configuration hierarchy. The configuration section it refers to can then be specified as often as desired in other configuration files.

Example 22-2 shows a truncated version of the default machine.config.

Only a small subset of the actual entries in machine.config are included in Example 22-2. Also, the type attribute of each entry was edited to remove all but the class, and lines have been broken to enhance the readability.

 

Example 22-2. Truncated machine.config file

The first three declarations in machine.config are runtime, mscorlib, and startup. They are special because they are the only declarations that do not have corresponding configuration sections in the file.

In Example 22-2, many handler declarations are contained within tags, which allows nesting of elements. By loose convention, the name attribute of these tags corresponds to the namespace that contains the handlers. This groups all configuration sections that are handled out of the same namespace.

22.2.4 Configuration Sections

The configuration sections contain the actual configuration data. They each are contained within an element corresponding to the name of the section specified in the configuration section handler declaration. The following two configuration sections are equivalent:


 

and:

 requestEncoding="utf-8"
 responseEncoding="utf-8"

Configuration sections typically contain name/value pairs that hold the configuration data. They may also contain subsections.

machine.config contains, at most, one configuration section for each handler declaration. (Not all handler declarations have a configuration section actually associated with it.) If the handler declaration is contained within a tag, then its corresponding configuration section will be contained within a tag containing the name of the . This can be seen in Example 22-2 for system.net.

The sections that follow provide a description of each configuration section relevant to Windows Forms contained in the default machine.config. Other configuration sections are outside the scope of this book, including system.net, system.web, and system.runtime.remoting.

22.2.4.1 appSettings

appSettings allow you to store application-wide name/value pairs for read-only access.

The handler declaration for appSettings, shown in Example 22-2 and reproduced here (minus the Culture and PublicKeyToken portions of the type attribute):


 

indicates that the NameValueFileSectionHandler class handles appSettings. This class provides name/value pair configuration handling for a specific configuration section.

As seen in Example 22-2, the appSettings section in the default machine.config file is commented out. If it were uncommented, any setting placed here would apply to every application on this machine. More typically, you would add an appSettings section to an application configuration file that would be in the directory of the application you wish to affect.

Example 22-3 shows an application configuration file for a specific application with an appSettings section added to provide two application-wide values. The appSettings section is not contained within any higher-level tag other than .

Example 22-3. Application configuration file containing appSettings section



 
 value="server=YourSrvr; uid=YourID; pwd=YourPW; database=pubs" />
 
 

This appSettings section would be saved in a configuration file in the same directory as the executable for a given application, and these values could then be accessed anywhere within that application by referring to the static (shared, in VB.NET) AppSettings property of the System.Configuration.ConfigurationSettings class. This AppSettings property is of type NameValueCollection: give it the name of the key and it returns the value associated with that key.

For example, all the sample programs listed in Chapter 15 query the pubs database included with the default installations of SQL Server and Microsoft Access. Each program has the connection string hardcoded into the program, including the SQL Server user ID and password. This is a bad idea for two reasons:

  • If either the server or the password is changed, you must locate and update all the code lines in all the applications that use that connection string, and then you must recompile.
  • Hardcoding the connection string makes it very unwieldy to do development against a test server and then to deploy the live application against a production server.

Rather than hardcoding these connection strings, the application configuration file shown in Example 22-3 can be included in the application directory, or the highlighted code from Example 22-3 can be included in machine.config. In either case, your code could then refer to the appSettings in lieu of the actual connection string. In C#, you would replace this line of code:

figs/csharpicon.gif

string connectionString =
 "server=YourSrvr; uid=YourID; pwd=YourPW; database=pubs";

with this line:

figs/csharpicon.gif

string connectionString = ConfigurationSettings.AppSettings["PubsConnection"];

In VB.NET, you would replace this line of code:

figs/vbicon.gif

dim connectionString as String = _
 "server=YourSrvr; uid=YourID; pwd=YourPW; database=pubs"

with this line:

figs/vbicon.gif

dim connectionString as String = _
 ConfigurationSettings.AppSettings("PubsConnection")

Any data included in a configuration file is in plain text, clearly visible to anyone who looks at the config file. Therefore, depending on the projected distribution of your application, it may be a bad idea to use appSettings to hold passwords, unless you encrypt the string in the config file and decrypt it in your application. (Of course, any encryption scheme is potentially breakable to someone with enough time and motivation.)

appSettings work well for secure storage of passwords in ASP.NET applications because the application is hosted on a remote server, and browsers and hence, users are blocked from retrieving the config files.

The System.Configuration.ConfigurationSettings class is part of the System.Configuration namespace. Therefore, to use appSettings, you must reference that namespace in your code. Include the appropriate using or imports statement, respectively:

figs/csharpicon.gif

using System.Configuration;

figs/vbicon.gif

imports System.Configuration

22.2.4.2 system.diagnostics

The system.diagnostics configuration section contains settings relating to the use of the System.Diagnostics Trace and Debug classes in your applications. These classes let you instrument your application for tracing and debugging without having to recompile the code.

To use tracing or debugging, compile the application with the appropriate flag. This process is discussed in Section 22.4.

The default system.diagnostics configuration section from machine.config is shown in Example 22-2; you can also add additional system.diagnostics sections to application configuration files.

The tags allow you to add switches and set their values, remove a specific switch, and clear all switches. The value of a switch can be tested using the properties of the TraceSwitch and BooleanSwitch classes, and depending on the result, appropriate action will be taken.

The tag in the default machine.config file has attributes to set the values of the AutoFlush and IndentSize properties of the Trace class:


 

22.2.4.3 system.net

The system.net configuration section contains subsections that deal with the .NET runtime. These subsections include authenticationModules, defaultProxy, connectionManagement, and webRequestModules. These subsections are outside the scope of this book.

22.2.4.4 system.web

The system.web configuration section contains subsections that configure ASP.NET. For a complete description of these sections, please refer to our book Programming ASP.NET (O'Reilly).

22.2.4.5 system.windows.forms

The default machine.config file contains only a single attribute in the system.windows.forms configuration section, and even then the entire single-line section is commented out. It is reproduced here from Example 22-2.

The jitDebugging attribute controls just-in-time debugging, which is disabled by default. Uncommenting this line and setting this value to true enables just-in-time debugging. When just-in-time debugging is enabled, a special dialog box appears when the program crashes, offering the user the opportunity to start one of the installed debuggers.

Visual Studio .NET controls just-in-time debugging independently of the configuration files. Click on Tools Options Debugging Just-In-Time. Two checkboxes enable just-in-time debugging for CLR programs and script programs. By default, these checkboxes are checked.

For a more complete discussion of JIT debugging, see Mastering Visual Studio .NET by Chris Sells, Jon Flanders, and Ian Griffiths (O'Reilly).

 

22.2.4.6 system.runtime.remoting

The system.runtime.remoting configuration section contains subsections that control remoting, which is the process of using an object residing in a different process or on a different machine. The details of this configuration section are beyond the scope of this book.

22.2.5 Custom Configuration

In addition to all the predefined configuration sections, you can add your own custom configuration sections. You might wish to add two different types of custom configuration sections:

  • Sections that provide access to a collection of name/value pairs, similar to appSettings.
  • Sections that return any type of object.

22.2.5.1 Name/Value pairs

In Example 22-3, you added an tag to store the database connection string. Suppose you wanted to store connection strings for multiple databases, say one called Test (for testing purposes) and one called Content (to hold the production content). A custom configuration section returning a name/value pair would be one way to handle this situation.

The lines of code inserted into a configuration file to accomplish this task are shown in Example 22-4. Adding a custom configuration section that returns a name/value pair requires the following steps:

  1. Determine which configuration file you will use to hold the custom section. This file determines the scope, or visibility, of the custom section.

    Adding the section to machine.config will make it available to every application on that machine. Adding it to an application configuration file will make the section visible only to that application.

  2. Declare the section handler by adding a line to the section of the designated configuration file. This tells the CLR to expect a configuration section with the specified name and which class and assembly file to use to process the section.

    Add the highlighted lines between the tags in Example 22-4 to the designated configuration file. If the file you are editing does not already have the opening XML declaration line, the tags, or the tags, then you will need to add them as well.

    The PublicKeyToken is part of the strong name of the file that contains the NameValueFileSectionHandler class, System.dll, supplied as part of the .NET Framework. The value of the PublicKeyToken is copied from a reference to that file in machine.config. For a complete discussion of strong names, please refer to Section 22.3.7 later in this chapter.

  3. Add the custom section itself to the configuration file. This section consists of the highlighted lines in Example 22-4 containing the tags. This custom configuration section contains two entries, one named Test and the other named Content, each with its own value attribute.

Example 22-4. Custom sections in configuration files

type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> value="SERVER=Server1;DATABASE=Test;UID=YourID;PWD=secret;" /> value="SERVER=Server2;DATABASE=Content;UID=YourID;PWD=secret;" />

The lines of code in Example 22-4 are wrapped for readability. The configuration files are sensitive to new line characters, so it is safest to make each line contiguous.

 

Note that the type in the

tag is nearly the same as that provided for appSettings in the machine.config file. It specifies the NameValueSectionHandler class in the System.dll assembly file

The appSettings section handler specified in the machine.config file refers to the NameValueFileSectionHandler class, while the altDB section handler created in Example 22-4 refers to the NameValueSectionHandler class, both of which are contained in System.dll. The classes seem interchangeable. Only the latter is documented in the SDK as being a member of the System.Configuration namespace hierarchy.

 

To read the contents of this custom configuration section, use the GetConfig method from the ConfigurationSettings class, as demonstrated in Example 22-5 in C# and in Example 22-6 in VB.NET. These examples create a very simple form with two buttons: one labeled Test and one labeled Content. Clicking on either button displays the appropriate connection string from the configuration file listed in Example 22-4.

Remember that if the code from Example 22-4 is contained in a stand-alone application configuration file rather than machine.config, then that configuration file must have the same name as the program executable with the added extension of .config. For example, if the C# version of the program is compiled to CustomConfigCS.exe, then the config file should be called CustomConfigCS.exe.config.

 

Example 22-5. Using custom configuration in C# (CustomConfig.cs)

figs/csharpicon.gif

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Configuration; //necessary for appSettings
using System.Collections.Specialized; //necessary for NameValueCollection
 
namespace ProgrammingWinApps
{
 public class CustomConfig : Form
 {
 Button btnTest;
 Button btnContent;
 
 public CustomConfig( )
 {
 Text = "Custom Configuration Demo";
 Size = new Size(300,200);
 
 btnTest = new Button( );
 btnTest.Parent = this;
 btnTest.Text = "Test DB";
 btnTest.Location = new Point(100, 50);
 btnTest.Click += new System.EventHandler(btnTest_Click);
 
 btnContent = new Button( );
 btnContent.Parent = this;
 btnContent.Text = "Content DB";
 btnContent.Location = new Point(btnTest.Left, 
 btnTest.Bottom + 25);
 btnContent.Click += new System.EventHandler(btnContent_Click);
 } // close for constructor
 
 static void Main( ) 
 {
 Application.Run(new CustomConfig( ));
 }
 
 private void btnTest_Click(object sender, EventArgs e)
 {
 string strMSg = ((NameValueCollection)
 ConfigurationSettings.GetConfig("altDB"))["Test"];
 MessageBox.Show(strMSg, "Test Connection String");
 }
 
 private void btnContent_Click(object sender, EventArgs e)
 {
 string strMSg = ((NameValueCollection)
 ConfigurationSettings.GetConfig("altDB"))["Content"];
 MessageBox.Show(strMSg, "Content Connection String");
 }
 } // close for form class
} // close form namespace

Example 22-6. Using custom configuration in VB.NET (CustomConfig.vb)

figs/vbicon.gif

Option Strict On
imports System
imports System.Drawing
imports System.Windows.Forms
imports System.Configuration 'necessary for appSettings
imports System.Collections.Specialized 'necessary for NameValueCollection
 
namespace ProgrammingWinApps
 public class CustomConfig : inherits Form
 
 dim btnTest as Button
 dim btnContent as Button
 
 public sub New( )
 Text = "Custom Configuration Demo"
 Size = new Size(300,200)
 
 btnTest = new Button( )
 btnTest.Parent = me
 btnTest.Text = "Test DB"
 btnTest.Location = new Point(100, 50)
 AddHandler btnTest.Click, AddressOf btnTest_Click
 
 btnContent = new Button( )
 btnContent.Parent = me
 btnContent.Text = "Content DB"
 btnContent.Location = new Point(btnTest.Left, _
 btnTest.Bottom + 25)
 AddHandler btnContent.Click, AddressOf btnContent_Click
 end sub ' close for constructor
 
 public shared sub Main( ) 
 Application.Run(new CustomConfig( ))
 end sub
 
 private sub btnTest_Click(ByVal sender as object, _
 ByVal e as EventArgs)
 dim strMsg as string
 strMsg = CType(ConfigurationSettings.GetConfig("altDB"), _
 NameValueCollection)("Test")
 MessageBox.Show(strMSg, "Test Connection String")
 end sub
 
 private sub btnContent_Click(ByVal sender as object, _
 ByVal e as EventArgs)
 dim strMsg as string
 strMsg = CType(ConfigurationSettings.GetConfig("altDB"), _
 NameValueCollection)("Content")
 MessageBox.Show(strMSg, "Content Connection String")
 end sub
 end class
end namespace

The highlighted lines of code in Example 22-5 and Example 22-6 are the calls to the GetConfig method. They are different for VB.NET and C#, and a bit confusing in both.

The GetConfig method takes a configuration section name as a parameter and returns an object of type NameValueCollection. The desired value in the collection is retrieved by using the key as an offset into the collection, using the get property syntax. In VB.NET, a property is retrieved by enclosing the property name in parenthesis, and in C#, the property is retrieved by using square brackets.

In both languages, the code first casts the value returned by GetConfig to type NamedValueCollection. In C#, this is required since that language does not support late binding. In VB.NET, late binding is supported by default, but since Option Strict is turned On in the first line of code in the program (almost always a good idea), this VB.NET program also disallows late binding.

In Visual Studio .NET, the default for Option Strict is Off. You can change this default by right-clicking on the project in the Solution Explorer and selecting Properties to view the Property Pages (not to be confused with the Properties window). Then go to Common Properties Build. There are drop-down menus for Option Explicit, Option Strict, and Option Compare. You can also change these for all projects by clicking on Tools Options Projects VB Defaults and setting the values in the drop-down menus.

 

If Option Strict were not turned on in VB.NET, thereby allowing late binding, you could forego the cast by substituting the following line of code for the equivalent highlighted line in Example 22-6:

figs/vbicon.gif

strMsg = ConfigurationSettings.GetConfig("altDB")("Test")

22.2.5.2 Objects

appSettings and custom configuration sections are very useful. However, they both suffer from the same limitation: they can return only a name/value pair. Sometimes returning an object would be very useful.

For example, suppose you have a standard query into a database. You could store the query string in an appSettings tag, then open a database connection after retrieving the string. However, it might be more convenient to store the query string in a configuration file and then have the configuration system return a DataSet directly.

To do this, add a

tag and a configuration section to the designated configuration file, as with the custom section returning name/value pairs, described in the previous section.

This example is presented only in VB.NET. The C# implementation is essentially the same, with only language syntax differences.

 

Edit the configuration file used in the previous example and shown in Example 22-4, adding the lines of code highlighted in Example 22-7.

Example 22-7. Returning objects from custom sections in a configuration file

type="ProgWinApps.Handlers.DataSetSectionHandler, vbSectionHandlers">

str="Select au_id,au_lname + ', ' + au_fname as name from authors" />

In a

section within the section, a handler declaration is created for the DataSetSectionHandler. This declaration specifies that elsewhere within the file, there will be a custom configuration section called DataSetSectionHandler. Furthermore, it specifies that the class handling that configuration section is called ProgWinApps.Handlers.DataSetSectionHandler, and that the class will be found in an assembly file called vbSectionHandlers.dll.

The two

sections in Example 22-7 differ in that one is self-closing while the other has a closing tag. They are equivalent and you can choose the one you prefer. As a rule, the self-closing tag is self-documenting in that you intend the element to have no contents (nothing between the open and close tags) while the paired tags indicate the opposite. If the element has children, of course, you have no choice but to use a pair of tags.

 

Further down in the configuration file, you will find a section called DataSetSectionHandler. It has a single attribute, str. This string contains the SQL statement you wish to pass to the database.

Next you must create the ProgWinApps.Handlers.DataSetSectionHandler class and place it in a source file called DataSetSectionHandler.vb, which will subsequently be compiled to vbSectionHandlers.dll. To do this, create a VB.NET source code file as shown in Example 22-8.

Example 22-8. Source code for section handler in VB.NET (DataSetSectionHandler.vb)

figs/vbicon.gif

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.XML
Imports System.Configuration
 
Namespace ProgWinApps.Handlers
 public class DataSetSectionHandler : _
 Implements IConfigurationSectionHandler
 
 public Function Create(parent as Object, _
 configContext as Object, _
 section as XmlNode) as Object _
 Implements IConfigurationSectionHandler.Create
 
 dim strSql as string
 strSql = section.Attributes.Item(0).Value
 
 dim connectionString as string = "server=YourServer; " & _
 "uid=YourID; pwd=YourPassword; database=pubs"
 
 ' create the data set command object and the DataSet
 dim da as SqlDataAdapter = new SqlDataAdapter(strSql, _
 connectionString)
 dim dsData as DataSet = new DataSet( )
 
 ' fill the data set object
 da.Fill(dsData,"Authors")
 
 return dsData
 end Function
 end class
end NameSpace

Be sure to set the connection string to match your specific database.

 

The database aspects of the code in this example are covered thoroughly in Chapter 19 and won't be discussed here in detail.

At the beginning of the Example 22-8 are several Imports statements (if written in C#, they would be using statements). Next, a namespace is declared to contain the class (to prevent ambiguity when calling the class).

For a class to be used as a configuration section handler, it must be derived from the IConfigurationSectionHandler interface. In VB.NET, this is implemented by using the Implements keyword. (In C#, this would be indicated with a colon between the class name and the inherited interface.)

A full discussion of the object-oriented concepts such as inheritance, base classes, and interfaces is beyond the scope of this book. For now, you remember that an interface acts as a contract that the implementing class must fulfill. The interface may, for example, dictate the signature of methods the implementing class must implement, or it may dictate which properties the class must provide. For a complete discussion of object-oriented concepts, see Programming C# or Programming Visual Basic .NET, both by Jesse Liberty (O'Reilly).

 

The IConfigurationSectionHandler interface has only a single method, Create. Therefore, your implementing class must implement the Create method with the specified signature. The three parameters are dictated by the interface. The first two parameters are rarely used and will not be discussed further. The third parameter is the XML data from the configuration file.

The XML node is parsed and the value of the first item in the Attributes collection of the tag (the str attribute) is assigned to a string variable in this line:

figs/vbicon.gif

strSql = section.Attributes.Item(0).Value

Once the SQL string is in hand, the connection string is coded, a SqlDataAdapter object is instantiated and executed, and the DataSet is filled. Then the DataSet is returned.

You could have also obtained the connection string in Example 22-8 from the configuration file, as demonstrated in Example 22-3 and Example 22-4. Leaving the connection string in this class (which will be compiled) has the benefit of hiding it from prying eyes a bit more securely (although nothing is totally secure from dedicated snoops), but it sacrifices the advantages of configuration files mentioned in previous sections.

 

Before this class can be used, it must be compiled. Open a command prompt by clicking on the Start button, and then Programs Microsoft Visual Studio .NET 2003 Visual Studio .NET Tools Visual Studio .NET 2003 Command Prompt. Use the cd command to make current the directory that will contain the application. Then enter the following command line:

vbc /t:library /out:vbSectionHandlers.dll /r:system.dll,System.data.dll,
System.xml.dll DataSetSectionHandler.vb

Chapter 2 explains how to use command-line compilers. Here the target type of the output is set to be library (a DLL). The name of the output file will be vbSectionHandlers.dll. Notice that three DLL files are referenced. The input source file is DataSetSectionHandler.vb. When the source file is compiled, you will have the output DLL in the current directory, where the classes it contains will be available to the application automatically.

Rather than creating this DataSetSectionHandler class as a separate source code file and DLL, you could embed the class directly in the application that uses it, obviating the need for the compilation step. Doing so, however, prevents you from reusing the code in multiple applications.

 

The application shown in Example 22-9 (in VB.NET) shows how to use this configuration section. This is similar to the application seen in Example 15-17 in Chapter 15, modified to get the dataset from the configuration file.

Example 22-9. Section handler demonstration in VB.NET (ListBoxItems-CustomConfig.vb)

figs/vbicon.gif

Option Strict On
imports System
imports System.Drawing
imports System.Windows.Forms
imports System.Data
imports System.Data.SqlClient
Imports System.Xml
imports System.Collections ' necessary for ArrayList
imports System.Configuration ' necessary for ConfigurationSettings
 
namespace ProgrammingWinApps
 public class ListBoxItems : inherits Form
 
 dim lb as ListBox
 
 public sub New( )
 Text = "ListBox Items Collection"
 Size = new Size(300,400)
 
 lb = new ListBox( )
 lb.Parent = me
 lb.Location = new Point(10,10)
 lb.Size = new Size(ClientSize.Width - 20, Height - 200)
 lb.Anchor = AnchorStyles.Top or AnchorStyles.Left or _
 AnchorStyles.Right or AnchorStyles.Bottom
 lb.BorderStyle = BorderStyle.Fixed3D
 
 ' get the data to populate the ListBox from pubs authors table
 dim ds as new DataSet( )
 ds = CType(ConfigurationSettings.GetConfig( _
 "DataSetSectionHandler"),DataSet)
 
 dim dt as new DataTable( ) 
 dt = ds.Tables(0)
 
 dim arlstNames as new ArrayList( )
 dim arNames( ) as object
 dim dr as DataRow
 lb.BeginUpdate( )
 for each dr in dt.Rows
 lb.Items.Add( _
 CType(dr("au_id"), string) + vbTab + _
 CType(dr("name"), string))
 next
 
 lb.Items.Add("12345" + vbTab + "Hurwitz, Dan")
 lb.Items.Add("67890" + vbTab + "Liberty, Jesse")
 lb.EndUpdate( )
 end sub ' close for constructor
 
 public shared sub Main( ) 
 Application.Run(new ListBoxItems( ))
 end sub
 
 end class
end namespace

The lines of code in Example 22-9 that differ from the original version of the program in Example 15-17 in Chapter 15 are highlighted. An additional namespace, System.Configuration, is imported. Several lines of code from the original program, reproduced here:

figs/vbicon.gif

dim connectionString as String = _
 "server=YourServer; uid=sa; pwd=YourPassword; database=pubs"
dim commandString as String = _
 "Select au_id,au_lname + ', ' + au_fname as name from authors"
dim dataAdapter as new SqlDataAdapter(commandString, _
 connectionString)
dim ds as new DataSet( )
dataAdapter.Fill(ds,"Authors")

are replaced with the highlighted lines from Example 22-9, reproduced here:

figs/vbicon.gif

dim ds as new DataSet( )
ds = CType(ConfigurationSettings.GetConfig( _
 "DataSetSectionHandler"),DataSet)

Rather than supply a connection string and SQL query string, a call is made to the static GetConfig method of the ConfigurationSettings class, which returns a DataSet object directly. Then the DataTable object is extracted from the DataSet. The parameter of the GetConfig method is a string containing the name of the section containing the configuration settings.

22.2.6 .NET Framework Configuration Tool (mscorcfg.msc)

This discussion about configuration has shown the actual configuration files that you can edit with any text editor or from within Visual Studio .NET. You can avoid some of the manual editing of standard config sections within configuration files by using the .NET Framework Configuration tool, mscorcfg.msc.

The .NET Framework Configuration tool, shown in Figure 22-2, is a Microsoft Management Console snap-in. It can be accessed by going to Control Panel and selecting Administrative Tools, and then Microsoft .NET Framework Configuration.

Figure 22-2. .NET Framework Configuration tool (mscorcfg.msc)

figs/pnwa_2202.gif

Having the .NET Configuration Tool available from within Visual Studio .NET is often convenient. It is easy to add it to the Tools menu. In Visual Studio .NET, click on Tools External Tools. Click on the Add button of the External Tools dialog box. Change the default tool name from [New Tool 1] to .NET Config Tool. In the Command field, enter mmc.exe. In the Arguments field, enter:

c:windowsmicrosoft.netframeworkversion numbermscorcfg.msc.

where version number is the version directory on your machine.

Most configuration handled by this tool involves assemblies.

Windows Forms and the .NET Framework

Getting Started

Visual Studio .NET

Events

Windows Forms

Dialog Boxes

Controls: The Base Class

Mouse Interaction

Text and Fonts

Drawing and GDI+

Labels and Buttons

Text Controls

Other Basic Controls

TreeView and ListView

List Controls

Date and Time Controls

Custom Controls

Menus and Bars

ADO.NET

Updating ADO.NET

Exceptions and Debugging

Configuration and Deployment



Programming. NET Windows Applications
Programming .Net Windows Applications
ISBN: 0596003218
EAN: 2147483647
Year: 2003
Pages: 148

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net