Custom settings are very easy to implement in .NET 2.0. In fact, if you don't care about the structure of your configuration data then the Visual Studio 2005 editor will actually do almost all the work for you - see
here. However, if you do care about the structure of your data, or you need to work with custom data types, or you want to store your settings in a custom configuration file then you will need to write a bit of code to pull everything together. Luckily, with .NET 2.0, it's pretty easy to write. Here is an example of creating a custom section containing a collection of custom elements. Just to make it interesting we'll add code to write everything out to a custom configuration file later. Let's begin with the code for the custom configuration element. Here is the listing:
public class CustomElement : ConfigurationElement
{
private static readonly ConfigurationProperty propName =
new ConfigurationProperty(
"name",
typeof(string),
string.Empty,
ConfigurationPropertyOptions.IsKey
);
private static readonly ConfigurationProperty propColor =
new ConfigurationProperty(
"color",
typeof(Color),
Color.Azure,
ConfigurationPropertyOptions.IsRequired
);
[ConfigurationProperty("name")]
public string Name
{
get { return (string)base[propName]; }
set { base[propName] = value; }
}
[ConfigurationProperty("color")]
public Color Color
{
get { return (Color)base[propColor]; }
set { base[propColor] = value; }
}
public CustomElement()
{
Properties.Add(propName);
Properties.Add(propColor);
}
}
The first thing to note about the CustomElement class is that it derives from the ConfigurationElement class. This class will do most of the heavy lifting related to storing & retrieving data for our configuration element. All that's left for us to do is to describe the data for the element - we do that by performing these steps:
- Add a static ConfigurationProperty to the class in order to describe each piece of data.
- Add a public property for each piece of data - and decorate each property with a ConfigurationProperty attribute.
- Add a reference to each static ConfigurationProperty field to the Properties collection on the base class.
That's it for the configuration element. Our element new contains a name and a color property. Next, let's create a collection class to hold instances of our custom configuration element. Here is the listing for the collection:
public class CustomElementCollection : ConfigurationElementCollection
{
public CustomElementCollection()
{
}
public void Add(CustomElement element)
{
BaseAdd(element);
}
protected override ConfigurationElement CreateNewElement()
{
return new CustomElement();
}
protected override object GetElementKey(
ConfigurationElement element
)
{
return ((CustomElement)element).Name;
}
}
The collection class derives from the ConfigurationElementCollection class - which handles most of the work involved with moving collections of data to and from a configuration file. The only additional work we had to perform was:
- Create a public method to add instances of our CustomElement class (The Add method)
- Override the CreateNewElement method, and use it to create instances of our CustomElement class.
- Override the GetElementKey method, and use it to return the name property. (This could be used to return any property that uniquely identifies your element.
See, we haven't written much code and we are almost finished! Let's wrap everything up by create a custom configuration section to read/write everything at runtime. Here is the listing:
public class CustomSection : ConfigurationSection
{
private static readonly ConfigurationProperty _propElements =
new ConfigurationProperty(
"Elements",
typeof(CustomElementCollection),
null,
ConfigurationPropertyOptions.IsDefaultCollection
);
[ConfigurationProperty("Elements")]
public CustomElementCollection Elements
{
get { return (CustomElementCollection)base[_propElements]; }
}
public CustomSection()
{
Properties.Add(_propElements);
}
public static CustomSection Read(string filePath)
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = filePath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(
fileMap,
ConfigurationUserLevel.None
);
return (CustomSection)config.Sections["CustomSection"];
}
public static void Write(string filePath, CustomSection section)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None
);
config.Sections.Add("CustomSection", section);
config.SaveAs(filePath, ConfigurationSaveMode.Full);
}
}
This class derives from ConfigurationSection, which takes care of the messy details involved in storing & retrieving data for the section. The only thing we need to add is a description of our custom data - in this case a collection of CustomElement objects. So, just like we did earlier, we add a static ConfigurationProperty to the class, then we add a public property for the collection, and decorate the property with a ConfigurationProperty attribute. Finally, we add the ConfigurationProperty to the Properties collection in the constructor. The only thing left to do is actually read and write the configuration data. The Read method demonstrates how to read our configuration data at runtime. We use an instance of the ExeConfigurationFileMap to tell .NET where to find our custom .config file. Then we perform the actual read operation using the OpenMappedExeConfiguration method on the ConfigurationManager object.
Writing our configuration data to a .config file is just as easy. The Write method uses the same mapping we saw in the Read method. We use the returned Configuration object a little differently. We write our configuration data by first adding our CustomSection object to the Sections property on the Configuration object, then calling the SaveAs method to actually write the XML to the .config file. Here is a quick example of how to read a CustomSection instance at runtime:
CustomSection section = CustomSection.Read("MyConfig.config");
Here is a quick example of how to write a CustomSection instance at runtime:
CustomSection section = new CustomSection();
CustomElement element = new CustomElement();
element.Name = "Test1"; element.Color = Color.Blue;
section.Elements.Add(element);
CustomSection.Write("MyConfig.config", section);
OK, that's my quick-and-dirty overview of reading and writing custom configuration data using the .NET framework. I hope someone will find this information helpful.
Have fun! 