The My feature in Visual Studio 2005 provides abbreviated access to many commonly used features in .NET. For example, My in Visual Basic .NET makes the common task of accessing settings in an application configuration (App.config) file easier. It does this by using the CodeDOM to generate a wrapper class for these commonly used features.
CodeDOM is both a namespace and a technology in the brilliantly crafted .NET Framework. The CodeDOM namespaces contain classes that take an object graph and generate code. One use of CodeDOM that’s been around a while is having the XSD.exe utility (XML Schemas) generate strongly typed DataSets.
This article shows you how Microsoft has taken the moderately difficult task of writing configuration settings as XML and reading those settings using objects and turned it into an easier process: using a visual designer and the My feature to access these settings. It starts by demonstrating how to use the ResourceManager and finishes by showing you the best way to access settings with the My feature in Visual Studio 2005 (and Visual Basic Express 2005).
Defining Read-Only Application Settings
XML is a language in its own right. In prior versions of .NET, you had to know how to write XML just to use an App.config file. If you were a happy VB6 camper, this could be a daunting task.
Don’t get me wrong; XML is a great language—especially for things like Web services, but I shouldn’t have to know it to use an App.config file. Thankfully, and finally, Microsoft has stuck a designer on top of the App.config file—at least as far as settings go—making this part of the framework accessible to XML neophytes. (Until just a few years ago, we were all XML neophytes.)
You can add application settings to an App.config file by adding an App.config file to your project and creating an <appSettings> section in that XML file. But, let’s skip right over that and use the new designer. To modify both application-level and user-level settings, click View|app_name Property Pages and click on the Settings tab (see Figure 1).
Figure 1: The Settings Tab of a Project’s Property Pages
The Settings tab is essentially the visual representation of a dictionary of name and value pairs. Figure 1 shows that type and scope attributes are permissible too.
To add an entry to the App.config file, provide a name (any name will do), pick an existing listed data type or browse to an assembly containing a data type, define the scope, and provide a value. The type defines the kind of value-editor that will be available—for example, picking the Color type will make the Color dialog available in the Value field (see Figure 2)—and the Scope quite simply indicates whether the value can be modified and isolates settings by user or application. Only User-scoped values can be modified.
Figure 2: The Color Type Makes the Color Dialog Available in the Value Field
Defining a Connection String
Creating a connection string will demonstrate the Settings page. If you scroll to the bottom of the Type list and pick (Connection String); then the Scope column will be fixed on Application and the Value column will have a button with an ellipses (…) for a name. When you click on this button, a Connection Properties dialog displays, facilitating the creation of a connection string (see Figure 3).
Figure 3: Selecting the (Connection String) Option for the Type
A connection string is generally an option that users aren’t permitted to change. You can define writeable—or user-changeable—settings by selecting a type and changing the Scope to User.
Defining Writeable User Settings
User settings may include an option that permits the user to change the size of the startup font, the default location of a form, or the home page layout. Really, user-modifiable options can be whatever you need them to be. To demonstrate, you can use a variation of the canonical Hello World sample application, store a string, retrieve that string, and permit the user to change the value of the string.
Define a writeable setting by opening the Settings tab of the project’s property
pages. Provide a name, type, and value for the setting, but the Scope has
to be User. For example, if you define a user-scoped setting named Foo, the
Settings page will modify the App.config file to look something like the XML
text in Listing 1 (Foo is in bold).
Listing 1: A Basic App.config File in Visual Basic .NET with a String User-Setting Foo
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=22.214.171.124, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="MySettings.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=126.96.36.199, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" /> </sectionGroup> </configSections> <connectionStrings /> <system.diagnostics> <sources> <!-- This section defines the logging configuration for My.Application.Log --> <source name="DefaultSource" switchName="DefaultSwitch"> <listeners> <add name="FileLog"/> <!-- Uncomment the below section to write to the Application Event Log --> <!--<add name="EventLog"/>--> </listeners> </source> </sources> <switches> <add name="DefaultSwitch" value="Information" /> </switches> <sharedListeners> <add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=188.8.131.52, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter"/> <!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log --> <!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> --> </sharedListeners> </system.diagnostics> <userSettings> <MySettings.My.MySettings> <setting name="Foo" serializeAs="String"> <value>This is the real stuff!</value> </setting </MySettings.My.MySettings> </userSettings> </configuration>
For the moment, you can ignore everything but the XML in bold. (It is also important to note that you don’t need to copy and paste this XML into any project; the Settings page and properties designer will generate it for you.)
Application and user settings are basically stored as name and value pairs (a dictionary, if you will). Even though VB.NET has no way of knowing the entries any of us will make, it can read this XML by using a custom section handler. For example, the <configSections> in Listing 1 indicates that a class named System.Configuration.UserSettingsGroup in the System.dll assembly should be loaded to handle XML in the <userSettings> block of the app.config.
Tip: You can write your own custom configuration file handlers by implementing the IConfigurationSectionHandler interface. (Refer to my earlier article Objectify an XML Node with an IConfigSectionHandler at for more information.
The initial settings are stored in the App.config file. Now you are ready to read and write them at runtime.
Accessing Settings Using the My Feature
In previous versions of .NET, you had to access settings using a ResourceManager, and by default these settings were read only. With .NET 2.0, user-scoped settings are writeable. So .NET takes two additional steps on your behalf.
Since .NET has generated a strongly-typed wrapper class and the settings
are accessible by coding My.Settings.settingsname,
you can read or write user-scoped settings. For example, to access Foo from
Listing 1, you can write My.Settings.Foo. If Foo is on the right side of an
operator, a read operation happens. If Foo is on the left side of an operator,
a write operation occurs. However, the App.config file is not modified;
a partial copy of the configuration file named user.config in C:Document
and SettingsusernameLocal SettingsApplication Dataapplicationvendornameuniquenameversionnumber is
created. This file, if it exists, is read next time the userSettings are accessed.
To actually save changes to user settings, you have to call My.Settings.Save.
Using a specific copy of the user settings in a separate file has a couple of benefits. First, an individual user’s changes aren’t visible to other users. Secondly, the original settings can be restored from the App.config file by calling My.Settings.Reload. Listing 2 contains a sample that demonstrates how easy it is to use these advanced XML configuration files and save changes to user-scoped settings.
Listing 2: Code That Reads, Modifies, and Saves Changes to User-Scoped Application Settings
Module Module1 Sub Main() Console.WriteLine(My.Settings.Foo) Console.ReadLine() My.Settings.Foo = "Bar" Console.WriteLine(My.Settings.Foo) Console.ReadLine() My.Settings.Save() End Sub End Module
If you are curious about what the settings wrapper class looks like or how to use the ResourceManager manually then click on Show all files at the top of the Solution Explorer and open the Settings.Designer.vb generated file.
Abstraction Is Progress
For the state of our art to continually progress, we must work at ever higher levels of abstraction. Microsoft clearly has its eye on the ball with the .NET Framework. Using XML to store configuration settings is a great idea, but having to learn XML before you can do so is really unacceptable as a productivity standard.
The .NET 2.0 Framework is better than ever and ready for prime time. It will be interesting to see how increasingly higher levels of abstraction yield productivity improvements, and cool core technologies like the CodeDOM fuel the effort.
About the Author
Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his new book UML DeMystified from McGraw-Hill/Osborne and his upcoming book C# Express for the Professional Programmer from Addison Wesley (Spring 2006). Paul is an architect for Tri-State Hospital Supply Corporation. You may contact him for technology questions at [email protected].
If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org.