You have to choices to store application data when working with the .NET Framework. The first opportunity is to hard-code it, the second is to use external, XML-based configuration files. The .NET Framework has a whole hierarchy of these files. On the top of it lives the machine.config. This configuration file is machine-wide, all managed applications refer to it.
When you are working with web applications, the hierarchy can have numerous levels. For standard (desktop) applications, there’s only one more level, the application configuration file of the current program. This typically has the name of TheApplicationName.exe.config.
First, let’s set out the rules. If you’d like to read from a configuration file from your code, you’ll require rights for reading all configuration files which plays a role in your application, back to machine.config. To modify configuration files from code, you’ll need the reading rights mentioned before, and writing rights to the application’s configuration file.
First I’d like to introduce the deprecated methods of dealing with configuration files. The first is the ConfigurationSettings class. This class has no constructors defined, and provides only a static property, called AppSettings, which queries the appSettings section of a given XML configuration file. It defines a static method called GetConfig, which returns the specified configuration section as an object. Crappy.
The way more cooler method is to use the static methods of the ConfigurationManager class. It defines two static properties, called AppSettings, which is essentially the same as it was in the disgusting ConfigurationSettings class, and ConnectionStrings, which allows programmatic access for the connectionStrings section of the exe’s configuration file, a feature what ConfigurationSettings can’t even imagine. And now the methods:
- GetSection: returns the string-specified configuration section as an object. But it will get better!
- OpenExeConfiguration: opens the configuration file associated with the given application and returns it as a Configuration object. Takes a member of the ConfigurationUserLevel enumeration.
- OpenMachineConfiguration: returns a Configuration class with the values of machine.config.
- OpenMappedExeConfiguration: opens a different exe configuration file. If it’s not possible (the path is invalid) it returns the current exe configuration as a strongly-typed Configuration class.
- OpenMappedMachineConfiguration: the same as the previous, but with machine.config.
- RefreshSection: refreshes a given section (re-read it from the disk).
I mentioned the ConfigurationUserLevel enumeration. Here are the values and their meanings:
- None: gets the Configuration that applies to all users.
- PerUserRoaming: gets the roaming configuration file for the current user.
- PerUserRoamingAndLocal: gets the local configuration file for the current user.
In a configuration file, there are many sections. For example, system.diagnostics is a configuration section. It defines properties such as trace or performanceCounters. But to confuse everyone, system.diagnostics is also a ConfigurationElement, because the base class of ConfigurationSection is ConfigurationElement. A ConfigurationElement represents a configuration section that is serialized into XML. A ConfigurationElement creates an internal collection of ConfigurationElementProperty classes, these are the attributes, or child elements of it.
OK, it’s a bit confusing, and I think you’ll spend a great deal of time to figure it out on MSDN, I’ll provide the links at the end of the post. When you’ve edited your configuration file, you’ll need to save it. It’s just as simple as calling the Configuration class’s Save method. You should specify a member of the ConfigurationSaveMode enumeration, and a Boolean value indicating whether or not saving should be forced (to save back the values even when you didn’t make any changes). ConfigurationSaveMode has the following members: Full, which saves back everything, Minimal, which saves back only properties that differ from inherited values, and Modified, which writes back only modified values, but even those whose value is the same as the inherited value.
There are a few interfaces you should be familiar with:
- IConfigurationSectionHandler: this one is deprecated from .NET 2, inherit from ConfigurationSection instead. It defines an object method which allows you to modify the contents of the XML node directly.
- ISettingsProvider: defines a single method the SettingsProvider GetSettingsProvider(SettingsProperty). Use it to define custom settings providers.
- IApplicationSettingsProvider: defines advanced methods to work with custom settings providers.
- IConfigurationSystem: MSDN says: “This interface supports the .NET Framework infrastructure and is not intended to be used directly from your code.”. I think that’s called inconsistency. How should we learn something of which all the available information is that we shouldn’t use it?
As I review this post I see that I don’t understand the hierarchy of configuration classes, so I think I’ll post an update when I’m more prepared. Until then, you could read MSDN, I will certainly do that.