mong the many new features in the forthcoming .NET 2.0 are the revamped System.Configuration namespace and the Visual Studio 2005 configuration editor. The new classes raise configuration for both desktop and Web applications to a new level of sophistication compared to prior implementations. The sheer size of the changes could fill a small reference text, so this article focuses on a very simple desktop application whose only purpose is to display and modify content from its own configuration file. To run the sample application you need to download the Visual Studio 2005 public beta. I used the February 2005 Professional Edition for all the screenshots and code builds.
Some New Features
Two of the most important new configuration file features are strong data typing for type safety and a separate and editable scope for user settings.
Type Safety
The previous version of the .NET Framework only allowed for string settings. This could create problems when reading settings directly into non-string variables, as seen in the code fragment below:
int maxConnections = ApplicationSettings.AppSettings.Key ["MaxConnections"];
If the configuration content wasn’t a string, but instead represented some other data type, such as a Boolean, integer, or more complex data type, you had to write custom code to cast the string value or create and populate the appropriate object. In contrast, the new API has specific classes that handle all the basic data types and interfaces for implementing custom serializers. In addition the framework has built-in handlers for some of the more commonly used programmatic constructs such as data source connection strings and URLs.
Scopes
The new API delineates separate application and user settings using a concept called scopes. You use the Application scope for settings specific to the application such as connection strings and other values that drive the application itself, and are not prone to change. The User scope is for storing user-configurable application values such as the last screen position and the most recently used documents. Most importantly, the User scope stores default values for each setting. When the user changes these default values by using the application, the configuration file stores these updated values in a separate location. This is important because it protects the integrity of the application’s configuration file and keeps user-specific data with the user’s system profile. The configuration framework loads user-specific settings automatically in the background without any additional developer effort.
The ThisConfigEditor Application
The downloadable code for the sample application presented here, ThisConfigEditor (see Figure 1), is a simple tool that displays settings from its own configuration file. While simplistic, this application serves as an excellent jumping off point for the needs of most applications.
Visual Studio generates most of the files in this project automatically (see Figure 2).
|
|
The only file that needs direct work in a code editor is the ThisConfigEditor.cs file. This application does not require any special assembly manifest or resources and all the configuration settings are handled by Visual Studio’s new Properties Editor. When Visual Studio creates a new project it automatically generates a Properties folder and populates it with classes that wrap the configuration settings you generate with the Properties Editor. The Properties Editor updates the app.config file and the Settings.cs class file (the class wrapper around the generated properties) automatically, so you don’t need to work with either of these files manually; in fact, you should only do so after you have a thorough understanding of the underpinnings of the new configuration file markup. You can find a full explanation for the configuration file markup tags at Microsoft’s MSDN site.
![]() | ? |
Figure 3. The Properties Editor: You reach the configuration (settings) editor by double-clicking on the “Settings.settings” entry in the Solution Explorer. |
The Property Editor
Double clicking on the “Settings.settings” entry in the Solution Explorer launches the Properties Editor.
Figure 3 shows two configuration properties created for demonstration purposes; FilesDirectory and Connection. The Properties Editor grid lets you specify the name, the datatype, the scope (by default there are only two scopes: User and Application) and the value. The most interesting property here is the Connection setting. Selecting (Connection string) from the Type dropdown launches a series of dialogs (though interestingly enough not a wizard) for creating the connection string (shown in Figure 4 and Figure 5).
|
|
What Gets Generated?
All this work in the Properties Editor generates configuration settings and a great deal of code automatically. While it is beyond the scope of this article to dig into the content in detail, it is useful to take a look. If you open the app.config file in the downloadable code that accompanies this article, you can see what Visual Studio creates as the ThisConfigEditor.exe.config file when you build the project. Even more interesting is the Settings.Designer.cs source (available in the downloadable code). This class provides easy and direct access to each setting by name in a namespace subordinate to the application’s main namespace, in this case, Example.Properties, in a class called Settings. Notice that the properties relate to each configuration setting. An attribute decorating each property defines the scope in which the property resides and its default value. Because the Settings class inherits from the ApplicationSettingsBase class (a new collection class in the System.Configuration API), you can access the properties directly by name or you can enumerate all the configuration settings, which is what the ThisConfigEditor example does.
Enumerating Configuration Properties
The heart of the ThisConfigEditor’s display is the private PopulateListView method in the ThisConfigEditor.cs code file.
private void PopulateListView() { ListViewItem item = null; this.buttonUpdateSetting.Enabled = false; this.textBoxSettingValue.Enabled = false; this.listViewSettings.Items.Clear(); Properties.Settings settings = Properties.Settings.Default; foreach (SettingsProperty property in settings.Properties) { bool match = false; switch (_dt) { case DisplayType.All: match = true; break; case DisplayType.Application: foreach (System.Collections.DictionaryEntry attribute in property.Attributes) { if (attribute.Value is System.Configuration. ApplicationScopedSettingAttribute) { match = true; break; } } break; case DisplayType.User: foreach (System.Collections.DictionaryEntry attribute in property.Attributes) { if (attribute.Value is System.Configuration. UserScopedSettingAttribute) { match = true; break; } } break; } if (match) { item = new ListViewItem(property.Name); item.SubItems.Add(new ListViewItem.ListViewSubItem(item, property.PropertyType.ToString())); item.SubItems.Add(new ListViewItem.ListViewSubItem(item, settings[item.Text] as string)); item.Tag = property; this.listViewSettings.Items.Add(item); } } }
Switching the private enum field _dt (which relates to the selection in the form’s combo box determining which configuration properties to display: All, Application, or User) the code enumerates through the configuration properties. Each member of the collection is a SettingProperty instance (another new class in the System.Configuration API representing an individual configuration property) which in turn contains a collection of DictionaryEntry instances representing their various attributes. By iterating over this collection of attributes the code searches for matches to the appropriate scope-designating attribute to reflect the selection made in the combo box. After making a match, the code displays the configuration property by creating a new ListViewItem and adding it to the ListView on the form.
Author’s Note: The ponderous nature of this method reflects certain instabilities in the current .NET beta 1 as much as a desire for readability. |
Where Does It All Go?
So, after skimming over the code and running the application you can see the various configuration settings in the ThisConfigEditor.exe.config file. To understand what the configuration framework does, it’s worth exploring what happens when you change a User scoped setting (see Figure 6).
![]() | ? |
Figure 6. Changing the User Scoped Setting: The figure shows the process of changing a setting in the ThisConfigEditor sample application. |
The changed setting isn’t saved into the application’s configuration file; instead, the API creates a new directory for the application (if it doesn’t already exist) in the user’s profile where it adds a file called user.config (see Figure 7).
Separating the data by scope in this manner protects the integrity of the applications configuration file by keeping user-specific data with the user. Again, the .NET framework automatically loads user-specific content without requiring any intervention from developers. Notice that the last subdirectory corresponds to the version number of the application. This ensures that successive versions of the application will maintain their individual integrity and not interfere with each other if a property’s datatype changes.
Author’s Note: Be mindful of your application’s version stamp because any changes (such as auto-incrementing build numbers) will cause the framework to create a new directory with new User-scoped settings?the values won’t carry over from previous versions. This is undoubtedly behavior that testers as well as developers should be aware of. |
![]() | ? |
Figure 7. The New User Configuration File: The figure shows where the .NET framework saves the user’s configuration file for the sample application. |
Compact Framework Gets Short Shrift?Again
The Compact Framework implementation on the Pocket PC sometimes seems to be the unwanted stepchild of the .NET world. Its 1.0 implementation made no provision for the System.Configuration namespace or the registry. The beta documentation for 2.0 flags the Compact Framework for each of the class entries in the System.Configuration namespace, as it does for numerous of the classes in all the namespaces in the beta documentation, but the currently available bits do not support this.
One can only hope that this is merely a passing condition during the development phase of the new .NET platform, and that the release version will support the same configuration capabilities as the desktop version.