My Feature in VS 2005: Storing Application and User Settings, Page 2
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 Settings\username\Local Settings\Application Data\applicationvendorname\uniquename\versionnumber 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 firstname.lastname@example.org.
If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org.