User Application Settings
(by Joe Williams for Blayd Software)
Introduction
This article relates to the configuration system implemented in version 2.0 of the
.Net Framework and in particular the use of the system for configuring Windows Forms
applications. The .Net Framework has always included support for application configuration
settings, however, early releases of the framework only provided support for static
application level settings that were stored either at machine level in the machine.config
file or at application level in the app.config file. Version 2.0 of the .Net Framework
introduced the SettingsProvider class and the provider that has particular relevance
to this article, the LocalFileSettingsProvider class. The LocalFileSettingsProvider
class derives from the SettingsProvider class and is used by the configuration system
to persist configuration settings to an XML file with a .config extension.
Windows Forms developers can still store their application's configuration settings,
at machine level, in the machine.config file or at application level, in the app.config
file but with the introduction of the settings provider model, can now also store
user specific application configuration settings in a user.config file. In a typical
installation, the machine.config and an application's app.config file will both
be read only. We think that the machine.config file should never be written to from
application code and that system administrators should restrict write access to
the machine level settings of applications and the .Net Framework itself to as few
accounts as possible. Developers should also consider their application's app.config
file to be a read only resource. We should all be installing our applications under
the Program Files folder and by default folders and files in this location will
be read only to non-administrator accounts. We know that a lot of Windows XP users
run their applications under an administrator account and will therefore be able
to write to an application's app.config file but we should not assume this to be
the case. With the release and increasing take-up of Windows Vista we also have
to consider the implications of User Account Control (UAC), it is no longer safe
to assume that the user running your application will have administrator privileges
and will, therefore, have write access to your application's app.config file. We
should now all be designing and developing applications so that they can operate
under a normal user account. This may require abstracting or removing rarely used
functionality, such as certain file system or registry manipulation for example,
that needs an administrator account, to a separate administration assembly, this
assembly can then be specified as requiring elevated privileges.
A Windows Forms application designed to run under a user account in a least privilege
environment should contain application level configuration settings in the app.config
file that is installed, together with the application's assembly, into a publisher
and/or product specific sub folder under the Program Files folder. The app.config
file can store application level configuration settings that are applied by the
application regardless of the user and user level configuration settings that are
applied by default, these settings are read only and cannot or at least should not
be updated at runtime. Settings that can be updated by a user at runtime can now
be saved to a user specific configuration file named user.config. Therefore, at
runtime, an application should apply the application level configuration settings,
loaded from the app.config file, the user specific configuration settings, if there
are any for the current user, loaded from the user.config file or if there are no
user specific settings for the current user, the default user level configuration
settings, loaded from the app.config file. An application may also provide support
for application level configuration settings that a system administrator can specify
in the machine.config file to control certain operational functionality for all
users of the application. For example, an application may allow a system administrator
to disable a web search or update facility by adding the relevant setting to the
machine.config file.
The .Net Framework configuration system makes user and application level configuration
settings a lot quicker and easier to implement than explain and if you use Visual
Studio 2005 as your development environment the application settings designer makes
it a very simple task.
Creating User Application Settings
The core functionality for application settings is provided in the SettingsBase
abstract base class. In a Windows Forms application the ApplicationSettingsBase
abstract base class extends the SettingsBase class to provide the extra core functionality
likely to be required by a Windows Forms application. Application specific functionality,
in a Windows Forms application, is provided by deriving a concrete 'wrapper' class
from the ApplicationSettingsBase abstract base class. The base classes named here
can be found in the System.Configuration namespace.
Application settings are mapped to the properties of the ApplicationSettingsBase
derived concrete wrapper class. An application settings property can be application-scoped
or user-scoped, an application-scoped property will be saved to the app.config file
and a user-scoped property will have a default value saved to the app.config file
and a user specific value saved, at runtime, to the user.config file. Attributes
are used to distinguish between application-scoped and user-scoped application settings,
the ApplicationScopedSettingAttribute is used to specify an application-scoped application
setting and the UserScopedSettingAttribute is used to specify a user-scoped application
setting. An application settings property must be decorated with one of these two
mutually exclusive attributes to enable the property value to be persisted correctly
to the relevant configuration file. There are several other attributes, defined
in the System.Configuration namespace, that can be applied to an application settings
property. If you are creating your application settings properties manually i.e.
you are not using the Visual Studio 2005 application settings designer, you should
familiarize yourself with the available attributes. In addition to the two attributes
named above, one of which you have to apply, you will probably want to apply the
DefaultSettingValueAttribute to your application settings properties. As the title
of this article suggests we will be concentrating on user-scoped application settings
but the mechanics are the same for both types of settings, they are just persisted
and applied differently.
When you create a new CSharp Windows Forms project in Visual Studio 2005 a folder
named 'Properties' will be created under the main project folder. In the Properties
folder you will find, together with several other files, a file named Settings.settings
and a file named Settings.Designer.cs. The Settings.settings file contains the XML
definition of the user application settings. The Settings.Designer.cs file contains
the declaration for a partial class named Settings, which is derived from the ApplicationSettingsBase
abstract base class and represents the concrete wrapper class that will be used
to define the project's user application settings properties in code.
Things are a little different if you are using Visual Basic. When you create a new
VB Windows Forms project in Visual Studio 2005 a folder named 'My Project' will
be created under the main project folder. In the My Project folder you will find,
together with several other files, a file named Settings.settings and a file named
Settings.Designer.vb. The Settings.settings file contains the XML definition of
the user application settings. The Settings.Designer.vb file contains the declaration
for a partial class named MySettings, which is derived from the ApplicationSettingsBase
abstract base class and represents the concrete wrapper class that will be used
to define the project's user application settings properties in code.
The Visual Basic generated concrete ApplicationSettingsBase wrapper implementation
contains some extra code to automatically save the user application settings when
the application is closed. In .Net languages other than Visual Basic you will have
to explicitly save the user application settings from your own code, typically you
would do this by calling the (inherited) Settings.Default.Save() method from the
main Form's Closing event or from an overridden OnClosing method implementation.
The concrete wrapper instance generated by the Visual Studio 2005 applications settings
designer in both CSharp and Visual Basic is a synchronized singleton with an (inherited)
indexer that will get and set application settings properties in a thread-safe manner.
If you used the Visual Studio 2005 application settings designer to generate your
concrete application settings class you can access an application settings property
in Visual Basic using the object reference returned by the My.Settings property,
in CSharp you need to use the object reference returned by the Settings.Default
property. If you created your own custom application settings class (see below)
by deriving directly from the ApplicationSettingsBase class you will have to create
an instance of your custom application settings class, if it is not static or does
not have a static property that returns a singleton instance, before accessing any
of it's properties or methods from your code.
If you require finer control over the process or you are developing application
settings for a custom control you can create your own application settings wrapper
class by explicitly deriving your own concrete settings class from the .Net Framework's
ApplicationSettingsBase class.
When using the .Net Framework's configuration system application settings infrastructure
you can data bind your chosen application properties to user application settings.
You can, for example, data bind a Form's BackColor property to a user application
settings property named FormBackColor and have the value of the Form's BackColor
property set at runtime to the user's chosen back colour or a default back colour
if the user has not chosen their preferred back colour. If you use the application
settings designer in Visual Studio 2005 you do not even have to write any code,
as the designer will generated the required code and the user application settings,
through data binding, will automatically be assigned to the relevant properties.
The data binding feature does undoubtedly save time and effort however, you should
note that not all controls, custom controls or properties support data binding.
We appreciate that this is a pretty vague statement but investigating every control
and every control property to see if it supports data binding and noting how it
behaves when data bound would be a mammoth task and would be beyond the scope and
budget of this article. It is possible to specify a property's value as a user application
setting even if it does not support data binding but you will have to manually write
the code to retrieve the settings property value from the settings wrapper class
and assign the value to the relevant property, you will also have to manually set
the property's value in the settings wrapper class when it's value changes in the
application.
To create a sample user application setting using the Visual Studio 2005 application
settings designer, proceed as follows:
- Right click the project name in the Solution Explorer and choose Properties from
the context menu or choose <Project Name> Properties from the main Project menu.
- Select the Settings section in the Project Properties dialog.
- Enter the value
FormBackColor for the setting name, select System.Drawing.Color
for the type, User for the scope and the system colour Control for the default value.
- Save the settings.
The designer will generate the following property declaration in the settings class:
C# user application settings property in the Settings class
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Control")]
public global::System.Drawing.Color FormBackColor
{
get
{
return ((global::System.Drawing.Color)(this["FormBackColor"]));
}
set
{
this["FormBackColor"] = value;
}
}
VB user application settings property in the MySettings class
<Global.System.Configuration.UserScopedSettingAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Configuration.DefaultSettingValueAttribute("Control")> _
Public Property FormBackColor() As Global.System.Drawing.Color
Get
Return CType(Me("FormBackColor"),Global.System.Drawing.Color)
End Get
Set
Me("FormBackColor") = value
End Set
End Property
The generated code is pretty straight forward, although it is worth noting the use
of attributes to define the scope and default value of the user application settings
property and the delegation to the indexer inherited from the SetttingsBase class
to actually get and set the property's value. The global key word is used to refer
to a global namespace and avoid any ambiguity in the namespace identifiers.
User application settings are added to the app.config file to serve as the default
user specific value for the relevant property. If, at runtime, the current user
has not defined a custom value for the Form's BackColor property the value of the
user application setting in the app.config file should be used. If the user application
setting is data bound to the BackColor property, the assignment of the correct value
occurs automatically as part of the binding process.
After creating the FormBackColor user application settings property the app.config
file will be as follows:
C# app.config file with a single user
application setting. The UserSettings.Properties.Settings element name refers to
the type name (including namespaces) of the C# ApplicationSettingsBase derived settings
class.
<configuration>
<configSections>
<sectionGroup name="userSettings"
type="System.Configuration.UserSettingsGroup,
System, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<section name="UserSettings.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<UserSettings.Properties.Settings>
<setting name="FormBackColor" serializeAs="String">
<value>Control</value>
</setting>
</UserSettings.Properties.Settings>
</userSettings>
</configuration>
VB app.config file with a single user application
setting. The UserSettings.My.MySettings element name refers to the type name (including
namespaces) of the VB ApplicationSettingsBase derived settings class.
<configuration>
<configSections>
<sectionGroup name="userSettings"
type="System.Configuration.UserSettingsGroup,
System, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<section name="UserSettings.My.MySettings"
type="System.Configuration.ClientSettingsSection,
System,
Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<!-- irrelevant sections removed for clarity -->
<userSettings>
<UserSettings.My.MySettings>
<setting name="FormBackColor" serializeAs="String">
<value>Control</value>
</setting>
</UserSettings.My.MySettings>
</userSettings>
</configuration>
We now have a user application settings property that we can data bind to a Form's
BackColor property or set and retrieve from code.
To data bind the setting to the Form's BackColor property:
- Load the relevant Form into the forms designer and expand the (
ApplicationSettings)
item in the Properties Editor.
- Select the (
PropertyBinding) item and click the ... button to display the Form
properties that can be data bound.
- Scroll to and select the
BackColor property, click the down arrow button and
select FormBackColor from the available application settings.
- Click OK to confirm the selection in the Form properties dialog.
The user application setting FormBackColor is now data bound to the Form's BackColor
property and will be set automatically at runtime using either the default user
setting from the app.config file or if the user has specified a preferred back colour,
the user setting from the user.config file.
You can combine the two previous operations into a single operation by creating
the user application settings property in the Form properties dialog. Rather than
selecting an existing application setting property, click the new link and define
the application settings property in the resulting dialog.
If you prefer not to or can't data bind a user application setting to a control
property you can retrieve the setting value in, for example, the Form Load event
handler using code similar to the following example:
C# code to retrieve the value of the FormBackColor user application setting
this.BackColor = Settings.Default.FormBackColor;
VB code to retrieve the value of the FormBackColor user application setting
Me.BackColor = My.Settings.FormBackColor
Note
The FormBackColor user application setting is strongly typed as System.Drawing.Color
and can therefore be assigned directly to the relevant BackColor property.
The C# example requires a using <rootnamespace>.Properties; namespace statement in the
Form class.
A VB data bound user application setting will be saved, if it has changed, automatically
when the application is closed. Windows Forms applications written in other .Net
Framework languages, notable CSharp, are responsible for saving user application
settings from code. Typically, this is achieved by calling the (inherited) Settings.Default.Save() method
in the main form's Closing event handler.
The .Net Framework documentation is a bit confusing when specifying the configuration
file section name used for storing application-scoped settings. In some places it
states that application-scoped settings are stored under a section element named
appSettings and in other places it states that they are stored under a section element
named applicationSettings. In our experience, application-scoped settings are stored
under a section element named applicationSettings. The reason being, presumably,
to avoid confusion between manually created settings, which are stored in a section
element named appSettings and dynamically created settings. The documentation seems
to specify the user-scoped settings section element name correctly, as far as we are aware.
User-scoped application settings are stored, both in the app.config and the user.config
file, under a section element named userSettings.
User Application Settings Persistence
User application settings are saved to the app.config file to serve as the user
default values for their respective application properties. However, if and when
a user changes the value of one of the user application settings, the user specific
value is written to separate configuration file. Once again the .Net Framework documentation
is a bit confusing when specifying the name of the user specific configuration file.
The documentation specifies the file name, in various topics, as
<username>.config where <userName> is the account name of the current user,
literally named as 'username.config' and literally named as 'user.config'. In our experience,
the user application settings configuration file is literally named as 'user.config',
which considering that the file is written to a sub folder under the
Documents and Settings\<user name> folder make sense, as it is already
associated with a unique user identity in the folder name. Because the app.config
file is typically read only, the default user application settings should not be dynamically
updated at runtime. However, because of it's location, the user.config file can,
by default, be written to, therefore, user specific application settings can be dynamically updated at runtime.
Configuration settings are persisted or saved by a settings provider, user application
settings are, by default, persisted by an instance of the LocalFileSettingsProvider
class. Your code does not have to interact with the settings provider, the configuration
system uses the provider specified by the SettingsProviderAttribute of the application
settings wrapper class. If your application settings wrapper class does not specify
this attribute the configuration system uses the LocalFileSettingsProvider class
to persist user application settings to an XML file with a .config extension.
The exact location of the user.config file can also be confusing, the .Net Framework
documentation states that the user.config file is persisted, when using the LocalFileSettingsProvider,
to the folder that is the equivalent of the following property:
System.Windows.Forms.Application.LocalUserAppDataPath
or the following property for a roaming user:
System.Windows.Forms.Application.AppDataPath
These two properties, typically, return the following values for Windows XP and
Windows Vista machines:
Local user on Windows XP:
%SystemDrive%\Documents and Settings\userName\Local Settings\Application Data\companyName\productName\version
Local user on Windows Vista:
%SystemDrive%\Users\userName\AppData\Local\companyName\productName\version
Roaming user on Windows XP:
%SystemDrive%\Documents and Settings\userName\Application Data\companyName\productName\version
Roaming user on Windows Vista:
%SystemDrive%\Users\userName\AppData\Roaming\companyName\productName\version
The itialicised values are retrieved as follows:
- userName
- The account name of the user running the application i.e. the current user.
- companyName
-
Retrieved from the assembly's
AssemblyCompanyAttribute. If the attribute is missing
or empty the assembly file base name is used i.e. the file name without the extension.
- productName
-
Retrieved from the assembly's
AssemblyProductAttribute. If the attribute is missing
or empty the assembly file base name is used i.e. the file name without the extension.
- version
-
Retrieved from the assembly's
AssemblyVersionAttribute. If the attribute is missing
the value '0.0.0.0' is used.
This seems to be pretty straight forward and indeed logical, however, in our experience
this is not what happens. For example, we created a simple application with a company
attribute of 'Blayd Software', a product attribute of 'User Settings', a version
attribute of '1.0.0.0' and an assembly file name of UserSettings.exe. Then, using
the Visual Studio 2005 designer, we bound the Form.BackColor property to a user
application configuration setting named FormBackColor, specifying the LocalFileSettingsProvider.
When we ran the application for the first time from within the Visual Studio 2005
environment, the configuration system created the following folder on a Windows
XP machine:
%SystemDrive%\Documents and Settings\userName\Application Data\Blayd_Software\UserSettings.vshost.exe_Url_mnslbjxhwd5xheqbajgbllfe1x5mw1ar\1.0.0.0
When we ran the application for the first time, outside of the Visual Studio 2005
development environment, the configuration system created the following folder on
a Windows XP machine:
%SystemDrive%\Documents and Settings\userName\Application Data\Blayd_Software\UserSettings.exe_Url_mnslbjxhwd5xheqbajgbllfe1x5mw1ar\1.0.0.0
In both cases the folder contained a user.config file with the default user application
setting value. We ran a similar test on a Windows Vista test machine and got the
same result. We did not run the test from within the Visual Studio 2005 environment
as we don't have a Vista machine with Visual Studio 2005 installed, we are sticking
with XP for development, for now!
There are several points worthy of note here, firstly, when running in the Visual
Studio 2005 environment, the folder naming convention uses the name of the vshost.exe
process which is used by Visual Studio 2005 to run Windows Forms applications. So
if you test your application inside and outside Visual Studio 2005 don't be surprised
if your user application settings values are different in each set of tests, as
they will be using different user.config files. Secondly, the folder naming convention
is nothing like the value returned by the System.Windows.Forms.Application.LocalUserAppDataPath
property. The folder naming convention used by the LocalFileSettingsProvider is
strikingly similar to that used by the isolated storage architecture, so we assume
that this naming convention is required to provide the required level of isolation
across the various .Net Framework installation platforms. Changing a user application
setting at runtime works fine, the user.config file gets updated, as you would expect,
and the value in use at application closedown is restored when the application is
next run. Therefore, if you stick with the configuration system to access the user.config
file everything will work fine, however, if for some reason you want to access the
user.config file from your own code, finding it could be a challenge.
Custom Application Settings Provider
The ApplicationSettingsBase derived concrete wrapper class manages the getting and
setting of application settings, however, it does not persist or retrieve the settings
to and from storage, this responsibility is handled by an application settings provider.
An application settings wrapper class is associated with an application settings
provider by applying the SettingsProviderAttribute either at the class level or
at the individual property level. Therefore, a single application settings provider
may be used to persist all of the settings properties or an individual settings
property may specify it's own settings provider. By default, if an application setting
provider is not specified by a settings property or an application settings wrapper
class, the LocalFileSettingsProvider is used to persist application settings to
an XML file with a .config extension.
Given the loose coupling between the application settings wrapper class and the
settings provider it is relatively easy to specify an alternative settings provider
class, however, you will probably have to develop the provider class yourself. To
demonstrate the steps required when developing an application settings provider
and to offer a slightly different approach from that implemented by the LocalFileSettingsProvider
we have developed our own application settings provider class. We can't show all
of the code in the custom settings provider in this article but we will outline
the specification, describe how to use the custom provider and describe the functionality
of the main, public, methods.
You can download the full source code, using the link provided in the "Article Options" on the left of
the page, for the custom application settings provider
class UserAppSettingsProvider as part of either a CSharp or a Visual Basic demonstration
Visual Studio 2005 project. The source code is intended, primarily, to demonstrate
how to develop a custom application settings provider, however, you can make use
of the code either in full or in part in your own applications without charge (see
the copyright and disclaimer notice in the UserAppSettingsProvider class for full
details).
The LocalFileSettingsProvider does a pretty good job of persisting application settings
to an XML file, however, it does introduce two new sections, applicationSettings
and userSettings to the configuration file and they are both relatively verbose.
In addition there is no capability to protect or encrypt user-scoped settings stored
in the user.config file. Our custom application settings provider, implemented in
the UserAppSettingsProvider class, also persists application settings to an XML
file, however, it writes the settings to the appSettings section which, by default,
is defined in the machine.config file and therefore does not require a definition
in the app.config file. The appSettings section stores configuration data in a simple
and relatively concise way as key value string pairs and the settings data can be
protected or encrypted.
In a typical .Net Framework installation you cannot declare an appSettings section
in the user.config file. You can override this default behaviour by adding an allowExeDefinition
attribute to the appSettings section declaration in machine.config and setting it's
value to MachineToLocalUser, however we would not recommend this as it would open
up the appSettings section of all Windows Forms applications on the machine. The
UserAppSettingsProvider class gets around the appSettings section limitation by
opening the user.config file as a mapped (external) configuration file with a configuration
user level of 'none' and the location specified as the user's local application
data path, you should note that roaming is not supported. Using this technique means
that the configuration system can be used to load and save the configuration settings
and features such as encryption are supported for the user application settings.
If you specify a protected configuration provider, the user application settings
will be encrypted when they are saved to the user.config file. If the user settings
are encrypted, they will be decrypted automatically when they are loaded from the
user.config file.
The UserAppSettingsProvider application settings provider does, therefore, subvert
one of the configuration system's built-in security mechanisms. We strongly recommend
that you do not do this if your provider is to be compiled into its own assembly
and used by other developers. The UserAppSettingsProvider application settings provider
is intended to be used in the application that it is serving and therefore the developer
using the provider has full access to the source code and can, therefore, make up
their own mind as to whether it is secure enough for their needs. As an added precaution,
the UserAppSettingsProvider class only reads from and writes to the appSettings
section in the user.config file for settings properties that are specified as user-scoped,
it only reads from the appSettings section in the app.config file, it does not write
to the app.config file. It also has a built-in arbitrary limit to the total size
of the key names and values that are written to and read from the user.config file.
You can, of course, alter or extend this functionality, to take account of disk
quota, for example.
The UserAppSettingsProvider application settings provider can be used with the CSharp
Settings class and the Visual Basic MySettings class generated by the Visual Studio
2005 application settings designer. To specify the UserAppSettingsProvider class
as the application settings provider you need to add the SettingsProviderAttribute
to either the Settings class or the MySettings class, for a Visual Basic project.
The SettingsProviderAttribute has two constructors, one that accepts the assembly
qualified name of the provider as a string and one that accepts the Type of the
provider. You can specify the UserAppSettingsProvider class as the application settings
provider as follows:
C# SettingsProviderAttribute declaration
[global::System.Configuration.SettingsProvider(typeof(UserAppSettingsProvider))]
VB SettingsProviderAttribute declaration
<Global.System.Configuration.SettingsProvider(GetType(UserAppSettingsProvider))>
When you use the Visual Studio 2005 designer to add or update a settings property
and save the changes, the designer regenerates the Settings or MySettings class
code from scratch, any code that you have manually added to the class will be deleted.
Therefore, we recommend that you create all of your settings properties before you
manually add the SettingsProviderAttribute to either the Settings or
MySettings class.
The Visual Studio 2005 application settings designer also generates an applicationSettings
and/or a userSettings section declaration and the relevant section values in the
app.config file. The UserAppSettingsProvider class does not require these values,
it will not do any harm if they are present in the app.config file, however, as
they are not used by the UserAppSettingsProvider we recommend that you, manually,
remove them. You will then need to, manually, add an appSettings section containing
the relevant settings property keys and their values. You should note that as the
UserAppSettingsProvider class utilizes the standard appSettings section, it will
only serialize and deserialize settings property types that can be converted to
and from a string representation. The app.config file application settings generated
by the designer, for a CSharp project, with a single user-scoped settings would
look similar to the following:
C# app.config file with a single, designer
generated, user-scoped property
<configuration>
<configSections>
<sectionGroup name="userSettings"
type="System.Configuration.UserSettingsGroup,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section name="UserSettings.Properties.Settings"
type="System.Configuration.ClientSettingsSection, System,
Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<UserSettings.Properties.Settings>
<setting name="DemoBackColor" serializeAs="String">
<value>Control</value>
</setting>
</UserSettings.Properties.Settings>
</userSettings>
</configuration>
When using the UserAppSettingsProvider the app.config file shown above can be amended
as follows:
C# app.config file with a single application-scoped
or user-scoped settings property that is to be handled by the UserAppSettingsProvider
class
<configuration>
<appSettings>
<add key="DemoBackColor" value="Control" />
</appSettings>
</configuration>
As with the settings properties, described above, the Visual Studio 2005 application
settings designer regenerates the app.config file values each time that a settings
property is added or updated and saved. Therefore, if you are using the designer
to create your settings, we recommend that you create all of the properties before
amending the app.config file so that it can be used by the UserAppSettingsProvider
class.
When creating settings properties either in an ApplicationSettingsBase derived class
generated by the application settings designer or in your own concrete wrapper class
and using the UserAppSettingsProvider class you can decorate the properties with
any of the application settings attributes.
However, the UserAppSettingsProvider class only explicitly recognises the following
attributes:
- UserScopedSettingAttribute
-
A settings property with this attribute will be written to the
user.config file
by the UserAppSettingsProvider the first time that the application is executed and
then closed. The first time that the application is executed, the value is read
from the app.config file, thereafter the value is read from the user.config file.
If the value of this property is changed, by the user, at runtime, the updated value
is written to the user.config file. A settings property must be decorated with either
the UserScopedSettingAttribute or the ApplicationScopedSettingAttribute. If a settings
property is not decorated with one of these attributes, application-scope is assumed.
It is an error to specify both of these attributes on a single settings property.
- ApplicationScopedSettingAttribute
-
A settings property with this attribute will be read, by the
UserAppSettingsProvider,
from the app.config file. The value of an application-scoped settings property will
never be written to either the app.config or the user.config file. A settings property
must be decorated with either the UserScopedSettingAttribute or the ApplicationScopedSettingAttribute.
If a settings property is not decorated with one of these attributes, application-scope
is assumed. It is an error to specify both of these attributes on a single settings
property.
- DefaultSettingValueAttribute
-
We strongly recommend that you apply this attribute to every settings property.
If the
UserAppSettingsProvider does not find a property's value in either the app.config
or the user.config file, the value of this attribute is assigned to the settings
property. If no value is found and the property is not decorated with this attribute,
the configuration system will assign null to reference type properties and the relevant
type default to value type properties, this may result in unpredictable behaviour.
- SettingsSerializeAsAttribute
-
The
UserAppSettingsProvider ignores settings properties that are not specified as
serialized as string. The UserAppSettingsProvider will not read or write settings
properties that cannot be serialized to or deserialized from a string representation.
You do not, however, have to explicitly apply this attribute to a settings property,
as the default is string serialization.
- NoSettingsVersionUpgradeAttribute
-
You should apply this attribute to settings properties that should not or cannot
be upgraded from a previous application version's value. The
UserAppSettingsProvider
tests each settings property for the presence of this attribute when processing
a call to the IApplicationSettingsProvider.Upgrade method, see below for further
details of this method.
The UserAppSettingsProvider class uses standard configuration system functionality
to read and write user application settings to and from the appSettings section in
the user.config file. Therefore, if the appSettings section is encrypted, the configuration
system will, automatically, decrypt the section data as it is loaded into memory
and will re-encrypt it when new or updated settings are written to the user.config
appSettings section. However, the user.config file is created, dynamically, at runtime
by the UserAppSettingsProvider class, therefore, typically, it is not practical
to manually encrypt the appSettings section before the application is executed for
the first time. It would be possible to create and encrypt the user.config file
during installation, for example or whilst manually setting up an application on
a machine, however, in most situations it is not practical or even possible to do
this. To facilitate the encryption of user application settings in the user.config
file, the UserAppSettingsProvider class can be instructed to explicitly encrypt
the settings, in code, the first time that it writes the user application settings
to the user.config file. The user application settings are only encrypted once,
thereafter the configuration system, automatically, handles the decryption, when
reading settings and the encryption when writing new or updated settings. To instruct
the UserAppSettingsProvider class to encrypt user application settings, you need
to specify the name of the relevant protected configuration provider in the settings
context that is passed to the provider when calling the SetPropertyValues, Reset
or Upgrade methods. This can be achieved by overriding the ApplicationSettingsBase.Context
property in the settings wrapper class and adding the friendly name of the required
protected configuration provider to the context that will be passed to the UserAppSettingsProvider
class.
To specify a protected configuration provider in a C# Settings
class, manually, add the following property to the class
public override SettingsContext Context
{
get
{
if (base.Context["ProtectionProvider"] == null)
{
base.Context["ProtectionProvider"] = "DataProtectionConfigurationProvider";
}
return base.Context;
}
}
To specify a protected configuration provider in a VB MySettings
class, manually, add the following property to the class
Public Overrides ReadOnly Property Context() As SettingsContext
Get
If (MyBase.Context("ProtectionProvider") Is Nothing) Then
MyBase.Context("ProtectionProvider") = "DataProtectionConfigurationProvider"
End If
Return MyBase.Context
End Get
End Property
The key must be as shown, including casing, the provider name value is the friendly
name of the protected configuration provider, not it's type name. You can, of course,
use a different provider or provider instance if required. The protected configuration
provider specified must be defined in either the machine.config or the user.config
file, typically, due to the dynamic creation of the user.config file, it will have
to be defined in machine.config. Encrypting the appSettings section in a
user.config file will, typically, protect the configuration data from someone trying to read
it on another machine, it will not necessarily protect it from a knowledgeable user
on the same machine. The level of protection depends on the provider that is used,
whether machine or user level protection is used and the access granted to the key
container, for the RSA provider.
A detailed discussion about protected configuration, the available providers and
their settings is beyond the scope of this article, however, if you want to know
more, the following article is a good starting point, Protected Configuration.
UserAppSettingsProvider is derived from the System.Configuration.SettingsProvider
abstract base class which in turn derives from the System.Configuration.Provider.ProviderBase
abstract base class. Application code does not, typically, directly call members
of the UserAppSettingsProvider class, the ApplicationSettingsBase class acts as
an intermediary to the actual application settings provider class and either (internally)
calls the provider itself, to retrieve settings property values, for example or
delegates to the relevant provider method, to reset the settings property values,
for example. Even though your application code will not, typically, call the UserAppSettingsProvider
class you may find it useful to know what is required of an application settings
provider, so we will outline the functionality of each of the public members. Most
of the actual processing carried out by the UserAppSettingsProvider class is done
by private helper methods, so you will need to look through the source code to gain
a full understanding of what it does and how it does it.
The following ProviderBase virtual method, is overridden by the UserAppSettingsProvider
class:
void Initialize(String name, NameValueCollection config)
In the case of an application settings provider both of the parameter values passed
to this member will, typically, be null. The UserAppSettingsProvider implementation
passes the value of a literal constant, which is set to 'UserAppSettingsProvider'
as the name when calling the base class implementation of Initialize. The base class
uses the value of the name parameter to initialize it's Name property which represents
the provider's friendly name. The base class version of this method tracks the number
of calls to Initialize for each provider and will throw an exception if it is called
more than once for a specific provider.
The following SettingsProvider abstract property is overridden by the UserAppSettingsProvider
class:
String ApplicationName { get; set; }
By default, the UserAppSettingsProvider class initializes this property to the following,
shortened application or assembly name:
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
However, the UserAppSettingsProvider class implements the property setter, therefore
the application name can be changed. The combination of the Name and ApplicationName
properties is used to resolve provider name conflicts.
The following SettingsProvider class abstract methods are overridden by the UserAppSettingsProvider
class:
SettingsPropertyValueCollection GetPropertyValues(SettingsContext context,
SettingsPropertyCollection collection)
This method is called by the application settings system to retrieve the values
of the settings properties. The context parameter is used to specify provider specific
values and is ignored by the UserAppSettingsProvider implementation. The collection
parameter is used to specify the settings properties to retrieve the values for,
the properties may be application-scoped and/or user-scoped. The first time that
this method is called i.e. the first time that the application executes, the UserAppSettingsProvider
class creates the folder that will contain the user.config file, it does not, however,
create the user.config file at this stage. The value of the following property is
used to name the user.config folder:
System.Windows.Forms.Application.LocalUserAppDataPath
See the User Application Settings Persistence section for more information about
how the value of this property i.e. the user.config folder name, is constructed.
The UserAppSettingsProvider class retrieves settings property values as follows:
If the property is application-scoped, the property value is retrieved from the
appSettings section in the app.config file. If a setting matching the name of the
property is not found in the app.config file, the property's default value is assigned.
If the property is user-scoped, the property value is retrieved from the appSettings
section in the user.config file. If the user.config file does not exist or if the
property is not found, the value is retrieved from the appSettings section in the
app.config file. If the property is not found in the app.config file, the property's
default value is assigned.
The method ignores properties that are not specified as serializable as string.
The method throws a ConfigurationErrorsException exception if a property contains
both the UserScopedSettingAttribute and the ApplicationScopedSettingAttribute attributes.
If a property does not contain either the UserScopedSettingAttribute or the ApplicationScopedSettingAttribute
attribute, application-scope is assumed.
void SetPropertyValues(SettingsContext context,
SettingsPropertyValueCollection collection)
This method is called by the application settings system to save the values of the
settings properties. In Visual Basic projects the MySettings class will automatically
call this method as the application is closing, however, in other .Net Framework
language projects e.g. CSharp the ApplicationSettingsBase.Save method will have
to be called explicitly from application code as the application is closing. The
first time that this method is called the user.config file is created, subsequently,
the settings property values are used to update the existing user.config file.
The context parameter is used to specify provider specific values and the UserAppSettingsProvider
implementation searches it for an entry with the key value of 'ProtectionProvider'
and a value specifying the friendly name of a protected configuration provider.
If a protected configuration provider name is found, the provider is used to protect
or encrypt the appSettings section in the user.config file. Protection is only explicitly
applied to the user.config file once, if the appSettings section is already encrypted
the configuration system will automatically re-encrypt it when the new or updated
settings property values are saved. If a protected configuration provider name is
not specified, the appSettings section is not protected. The collection parameter
is used to specify the settings property values to save and may contain the values
of application-scoped and/or user-scoped properties. However, the UserAppSettingsProvider
class only saves the values of user-scoped application settings properties, application-scoped
property values are ignored.
The UserAppSettingsProvider class implements the IApplicationSettingsProvider interface
which defines three methods for retrieving the value of the previous version of
a settings property, resetting settings properties to their default values and upgrading
settings from one version of an application to another. The methods of this interface,
described below, are intended to be called from application code, however, you do
not call them directly. The ApplicationSettingsBase class has three identically
named methods, each of which delegates to the settings provider's relevant IApplicationSettingsProvider
method. Therefore, to call one of the IApplicationSettingsProvider interface methods
from application code you would call the relevant method on the settings wrapper
class as follows:
C# application calling code for each
of the three IApplicationSettingsProvider methods
object value = Settings.Default.GetPreviousVersion(propertyName);
Settings.Default.Reset();
Settings.Default.Upgrade();
VB application calling code for each
of the three IApplicationSettingsProvider methods
Dim value As Object = MySettings.GetPreviousVersion(propertyName)
MySettings.Reset()
MySettings.Upgrade()
The UserAppSettingsProvider class implements the IApplicationSettingsProvider interface
methods as follows:
SettingsPropertyValue GetPreviousVersion(SettingsContext context,
SettingsProperty property)
This method is called via the ApplicationSettingsBase.GetPreviousVersion method
to retrieve the value of the specified settings property from the user.config file
of the previous version of the application. The context parameter is used to specify
provider specific values and is ignored by the UserAppSettingsProvider implementation.
The property parameter is used to specify the settings property whose value is to
be retrieved. The settings property must be user-scoped and must be specified as
serialized as string, otherwise it is ignored. The UserAppSettingsProvider class
searches through the sub folders under the user.config file's root folder looking
for the previous version of the application. If a previous application version user.config
file is found and it contains the value of the specified settings property, the
value is returned, otherwise this method returns null.
void Reset(SettingsContext context)
This method is called via the ApplicationSettingsBase.Resest method to reset all
user-scoped settings property values to the default values specified in app.config.
The context parameter is used to specify provider specific values and the UserAppSettingsProvider
implementation searches it for an entry with the key value of 'ProtectionProvider'
and a value specifying the friendly name of a protected configuration provider.
If a protected configuration provider name is found, the provider is used to protect
or encrypt the appSettings section in the user.config file. Protection is only explicitly
applied to the user.config file once, if the appSettings section is already encrypted
the configuration system will automatically re-encrypt it when the new or updated
settings property values are saved. If a protected configuration provider name is
not specified, the appSettings section is not protected.
The UserAppSettingsProvider resets all user-scoped settings properties in user.config
to the values specified in app.config. Any user-scoped settings properties that
cannot be found in app.config are left with their existing value. After this method
returns, the application settings system will reload the application settings. Any
settings properties that are data bound in the application will, therefore, revert
to their default value. Any settings properties that are not data bound in the application
will have to be explicitly updated to their default values in application code.
void Upgrade(SettingsContext context, SettingsPropertyCollection properties)
This method is called via the ApplicationSettingsBase.Upgrade method to migrate
user-scoped settings properties from one version of the application to another.
The context parameter is used to specify provider specific values and the UserAppSettingsProvider
implementation searches it for an entry with the key value of 'ProtectionProvider'
and a value specifying the friendly name of a protected configuration provider.
If a protected configuration provider name is found, the provider is used to protect
or encrypt the appSettings section in the user.config file. Protection is only explicitly
applied to the user.config file once, if the appSettings section is already encrypted
the configuration system will automatically re-encrypt it when the new or updated
settings property values are saved. If a protected configuration provider name is
not specified, the appSettings section is not protected. The
properties parameter is used to specify the settings property values to migrate and
may contain the values of application-scoped and/or user-scoped properties. However, the UserAppSettingsProvider
class only migrates the values of user-scoped application settings properties, application-scoped
property values are ignored.
The UserAppSettingsProvider class searches through the sub folders under the user.config
file's root folder looking for the previous version of the application. If a previous
application version user.config file is found and it contains the value of a settings
property specified in the properties parameter, the value is migrated, otherwise
it is ignored. After this method returns, the application settings system will reload
the application settings. Any settings properties that are data bound in the application
will, therefore, be set to the value specified by the user in the previous version
of the application. Any settings properties that are not data bound in the application
will have to be explicitly updated to their previous version values in application
code.
Conclusion
Saving application settings to the app.config file has always been problematic but
with the release of Windows Vista we should all assume that the user running our
application will definitely not have write access to app.config. The introduction
of the settings provider model in the .Net Framework has given developers much more
scope when persisting application settings. The default, out of the box, solution
of a user specific configuration file i.e. user.config, that a user will always
have write access to and can, therefore, be used to store dynamic application settings,
is perfectly adequate for most situations and Visual Studio 2005 with it's application
settings designer makes defining user application settings easy. If the ready to
run solution is not suitable, we now have much more flexibility and we can develop
and specify our own application settings provider to store application-scoped and
user-scoped settings property values in our preferred format and location.
Copyright ©Blayd Software Limited 2007-2010. All rights reserved.