By default .NET configuration can’t contain any CDATA or text elements and if you not experienced following message
The configuration section cannot contain a CDATA or text element
than you’re lucky!
So basically you can’t do something like this:
1 2 3 4 5 6 7 |
... <customSection> <settings> <name>Lorem ipsum</name> </settings> </customSection> ... |
If you look closely to ConfigurationElement
class you’ll notice 2 useful methods:
DeserializeElement
SerializeElement
The tick is to use above methods to overcome limitation of .NET configuration elements structure. These methos are responsible for saving to/reading from configuration file.
Let’s have a class that will represent <settings>
.NET configuration element
1 2 3 4 5 6 7 8 9 |
public class CustomConfigSectionSettingsElement : ConfigurationElement { [ConfigurationProperty("name", IsRequired = true)] public string Name { get { return (string)this["name"]; } set { this["name"] = value; } } } |
The configuration property Name
in class will represent XML <name>
element value so it’s value will be persisted using .NET configuration mechanism.
Next we’ll write custom model class (POCO, DTO, whatever you call it) that will represent our XML structure.
1 2 3 4 5 6 |
[XmlRoot(ElementName = "settings")] public class SettingsModel { [XmlElement(ElementName = "name")] public string Name { get; set; } } |
The key thing is to give your class, properties proper names which will be used in serialization/deserialization process.
The last thing that is missing is to write DeserializeElement
and SerializeElement
methods implementation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) { XmlSerializer ser = new XmlSerializer(typeof(SettingsModel)); var model = (SettingsModel)ser.Deserialize(reader); Name = model.Name; } protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey) { if (writer == null) return false; var model = new SettingsModel { Name = Name }; XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializer ser = new XmlSerializer(typeof(SettingsModel)); ser.Serialize(writer, model, ns); return true; } |
One thing to note here is to provide your own namespace otherwise you’ll end up with default that will spoil this pure XML strucure (visually).
So the final version of your custom configuration class looks like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class CustomConfigSectionSettingsElement : ConfigurationElement { [ConfigurationProperty("name", IsRequired = true)] public string Name { get { return (string)this["name"]; } set { this["name"] = value; } } protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) { XmlSerializer ser = new XmlSerializer(typeof(SettingsModel)); var model = (SettingsModel)ser.Deserialize(reader); Name = model.Name; } protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey) { if (writer == null) return false; var model = new SettingsModel { Name = Name }; XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializer ser = new XmlSerializer(typeof(SettingsModel)); ser.Serialize(writer, model, ns); return true; } } |
Given above implementation and XML configuration strucure now it’s possible to get your settings like you’d use .NET configuration:
1 2 3 |
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); var customSection = (CustomConfigSection)config.GetSection("customSection"); var nameValue = customSection.Settings.Name; |