back to the topic of why didn\'t .net provide a simple (i don\'t want to implement \"ConfigurationSection\" \"ConfigurationElement\" \"ConfigurationProperty\" for 2 val
You need to load the config file in the right way. Rather than using the static properties of ConfigurationManager
use the methods to load.
Also you need to ensure you are managing the difference between global, application, user roaming and user local configuration. Normally only the last two should be writeable.
Some test code for writing changes to the use config file:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
TestConfigData data = (TestConfigData)config.GetSection("testConfigData");
++data.Data;
config.Save(ConfigurationSaveMode.Minimal);
Where TestConfigDate is a custom configuration type:
using System;
using System.Configuration;
using System.Text;
namespace CustomConfiguration {
public class TestConfigData : ConfigurationSection {
[ConfigurationProperty("Name", IsRequired=true)]
public string Name {
get {
return (string)this["Name"];
}
set {
this["Name"] = value;
}
}
[ConfigurationProperty("Data", IsRequired=false),
IntegerValidator(MinValue=0)]
public int Data {
get {
return (int)this["Data"];
}
set {
this["Data"] = value;
}
}
}
}
And the configuration file contains, noting the allowExeDefinition
attribute on the section
element to define that a user configuration file and override the app.exe.config
:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="testConfigData"
type="CustomConfiguration.TestConfigData, CustomConfiguration"
allowExeDefinition="MachineToLocalUser"/>
</configSections>
<testConfigData Name="Fubar" Data="0"/>
</configuration>
Fire up reflector and take a look at the following method on System.Configuration.NameValueSectionHandler : internal static object CreateStatic(object parent, XmlNode section, string keyAttriuteName, string valueAttributeName).
Linda Liu from Microsoft Online Community Support gives some great information about NameValueSectionHandler, IConfigurationSectionHandler, and why a DefaultSection instance will be returned from Configuration.GetSection(string) in a discussion at the EggHeadCafe forums: Backwards compatibility of System.Configuration.Configuration.
It is technically possible to read, and create this information, but I recommend you not cause yourself more pain than you must by interacting at this extremely low level of the Configuration API. Please use the below code for Educational purposes only. I highly encourage you to use one of the methods like what Richard mentioned using the declarative style for creating a custom ConfigurationSection
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SingleTag" type="System.Configuration.SingleTagSectionHandler"/>
</configSections>
<SingleTag scheme="https" server="webmail.contoso.com" domain="CONTOSO" username="jdoe" password="iTz@s3Cr3t!"/>
</configuration>`
You could read this configuration section, but it's not good for your mental health.
Sample C# Code - Stick this inside your void Main(string[] args) and smoke it.
// Read configuration
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection readableSection = config.GetSection("SingleTag");
string readableSectionRawXml = readableSection.SectionInformation.GetRawXml();
XmlDocument readableSectionRawXmlDocument = new XmlDocument();
readableSectionRawXmlDocument.Load(new StringReader(readableSectionRawXml));
SingleTagSectionHandler readableSectionHandler = new SingleTagSectionHandler();
Hashtable result = (Hashtable)readableSectionHandler.Create(null, null, readableSectionRawXmlDocument.DocumentElement);
foreach (string item in result.Keys)
{
Console.WriteLine("{0}\t=\t{1}", item, result[item]);
}
// Create similar configuration section
Hashtable mySettings = new Hashtable();
mySettings.Add("key1", "value1:" + DateTime.Now);
mySettings.Add("key2", "value2:" + DateTime.Now);
mySettings.Add("key3", "value3:" + DateTime.Now);
mySettings.Add("keynull", null);
mySettings.Add("key4", "value4:" + DateTime.Now);
string rawData = string.Empty;
XmlDocument writableSectionXmlDocument = new XmlDocument();
XmlElement rootElement = writableSectionXmlDocument.CreateElement("CreateSingleTag");
foreach (var item in mySettings.Keys)
{
if (mySettings[item] != null)
{
rootElement.SetAttribute(item.ToString(), mySettings[item].ToString());
}
}
writableSectionXmlDocument.AppendChild(rootElement);
if (config.Sections.Get("CreateSingleTag") == null)
{
ConfigurationSection writableSection = new DefaultSection();
writableSection.SectionInformation.SetRawXml(writableSectionXmlDocument.OuterXml);
config.Sections.Add("CreateSingleTag", writableSection);
}
else
{
config.Sections["CreateSingleTag"].SectionInformation.SetRawXml(writableSectionXmlDocument.OuterXml);
}
config.Save();
For completeness sake - you need the following usings
using System;
using System.Collections;
using System.Configuration;
using System.IO;
using System.Xml;
and a reference to at least the following assemblies
System
System.Configuration
System.Xml