Bill van Melle

I have configuration files whose sections are simple key/value pairs, handled by System.Configuration.DictionarySectionHandler. E.g., here's a trivial one:

< xml version="1.0" encoding="utf-8" >
<configuration>
<configSections>
<sectionGroup name="foo">
<section name="bar" type="System.Configuration.DictionarySectionHandler,system, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null"/>
</sectionGroup>
</configSections>
<foo>
<bar>
<add key="MyKey" value="MyValue"/>
</bar>
</foo>
</configuration>

It's easy to read them if they're in my own configuration file:

IDictionary mysettings = (IDictionary)ConfigurationManager.GetSection("foo/bar");
Console.WriteLine("MyKey = " + mysettings["MyKey"]);

But I want to be able to read configuration file sections from a configuration file other than the default. This seems to require using code of this sort:

ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = "test4.exe.config";
Configuration otherconfig =
ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
ConfigurationSectionGroup group = otherconfig.SectionGroups["foo"];
ConfigurationSection section = group.Sections["bar"];

At this point I have the desired config section, but how do I get any values out of it I can't do this:

IDictionary othersettings = (IDictionary)section;

because section is of type DefaultSection, not a dictionary. This is documented ("[DefaultSection] is also returned when the type of registered section does not inherit from ConfigurationSection, as with sections that use the ASP.NET 1.0 or 1.1 IConfigurationSectionHandler type"). I can tell that it's my section, because section.SectionInformation.GetRawXml() has the correct content. But I don't see where to get at the object that DictionarySectionHandler supposedly created.

So what am I supposed to do Create my own new implementation of DictionarySectionHandler that is based on ConfigurationSection, and use that instead in all my config files

As a kludge, I considered passing that GetRawXml value to DictionarySectionHandler.Create(), but I can't quite get that to work, either.

string xml = section.SectionInformation.GetRawXml();
XmlDocument doc = new XmlDocument();
doc.Load(XmlReader.Create(new StringReader(xml)));
IDictionary dict = new DictionarySectionHandler().Create(null, null, doc) as IDictionary;

This code raises System.NullReferenceException in the Create call.



Re: .NET Base Class Library How to read values out of non-default configuration file?

CommonGenius.com

Not an expert on this topic, but have you tried using OpenExeConfiguration instead of OpenMappedExeConfiguration




Re: .NET Base Class Library How to read values out of non-default configuration file?

Bill van Melle

In fact, I have tried using OpenExeConfiguration. One of its overloads opens the default exe config (or some combination of them), which, as I wrote above, is not what I want. The other claims to take a path to a config file, but instead seems to take a path to an exe file, to which it appends ".config". That would almost work, if I assume the files I want to open always end in ".config". But that tangent aside, it doesn't matter. Both OpenExeConfiguration and OpenMappedExeConfiguration return System.Configuration objects, which don't seem to want to let me get at anything except objects of type ConfigurationSection, which the old-style handlers don't produce. Thanks anyway.

I think I'll probably end up changing my config files to use the new AppSettingsSection type, which is dictionary-like. It will be an incompatible config/code change, and won't work in .NET 1.1, but at least it's conceptually the same.




Re: .NET Base Class Library How to read values out of non-default configuration file?

Bluehunter

Hi friend, here I give you a complete source code of my own, not for commercial use, ok Wink

public sealed class TestParamsSection : ConfigurationSection

{

public TestParamsSection()

{

}

[ConfigurationProperty("testParameters", IsDefaultCollection = true)]

public ParamElementCollection TestParameters

{

get { return (ParamElementCollection)base["testParameters"]; }

}

}

[ConfigurationCollection(typeof(ParamElementCollection),AddItemName = "param")]

public sealed class ParamElementCollection : ConfigurationElementCollection

{

protected override ConfigurationElement CreateNewElement()

{

return new ParamElement();

}

protected override object GetElementKey(ConfigurationElement element)

{

return ((ParamElement)element).Name;

}

public override ConfigurationElementCollectionType CollectionType

{

get

{

return ConfigurationElementCollectionType.AddRemoveClearMap;

}

}

protected override string ElementName

{

get

{

return "param";

}

}

protected override ConfigurationElement CreateNewElement(string elementName)

{

return new ParamElement(elementName);

}

public new string AddElementName

{

get { return base.AddElementName; }

set { base.AddElementName = value; }

}

public new string ClearElementName

{

get { return base.ClearElementName; }

set { base.AddElementName = value; }

}

public new string RemoveElementName

{

get { return base.RemoveElementName; }

}

public new int Count

{

get { return base.Count; }

}

public ParamElement this[int index]

{

get { return (ParamElement)BaseGet(index); }

set

{

if (BaseGet(index) != null)

BaseRemoveAt(index);

BaseAdd(index, value);

}

}

new public ParamElement this[string Name]

{

get

{

return (ParamElement)BaseGet(Name);

}

}

public int IndexOf(ParamElement param)

{

return BaseIndexOf(param);

}

public void Add(ParamElement param)

{

BaseAdd(param);

// Add custom code here.

}

protected override void BaseAdd(ConfigurationElement element)

{

BaseAdd(element, false);

// Add custom code here.

}

public void Remove(ParamElement param)

{

if (BaseIndexOf(param) >= 0)

BaseRemove(param.Name);

}

public void RemoveAt(int index)

{

BaseRemoveAt(index);

}

public void Remove(string name)

{

BaseRemove(name);

}

public void Clear()

{

BaseClear();

// Add custom code here.

}

}

public sealed class ParamElement : ConfigurationElement

{

public ParamElement()

{

}

public ParamElement(string elementName)

{

Name = elementName;

}

public ParamElement(string name, string type, object value)

{

Name = name;

Type = type;

//Value = value;

}

[ConfigurationProperty("name", IsKey = true, IsRequired = true)]

public string Name

{

get

{

return (string)base["name"];

}

set

{

base["name"] = value;

}

}

[ConfigurationProperty("type", IsRequired = true)]

public string Type

{

get

{

return (string)base["type"];

}

set

{

base["type"] = value;

}

}

[ConfigurationProperty("value", IsRequired = true)]

[TypeConverter(typeof(ObjectStringConverter))]

public object Value

{

get

{

return (object)base["value"];

}

set

{

base["value"] = Convert.ChangeType(value, System.Type.GetType(Type));

}

}

public override string ToString()

{

string output = "ParamElement :\n";

output += string.Format("Name = {0}\n", Name);

output += string.Format("Type = {0}\n", Type);

output += string.Format("Value = {0}\n", Value);

return output;

}

}

public class ObjectStringConverter : TypeConverter

{

// Overrides the CanConvertFrom method of TypeConverter.

// The ITypeDescriptorContext interface provides the context for the

// conversion. Typically, this interface is used at design time to

// provide information about the design-time container.

public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)

{

if (sourceType == typeof(string))

{

return true;

}

return base.CanConvertFrom(context, sourceType);

}

/// <summary>

/// Overrides the ConvertFrom method of TypeConverter.

/// </summary>

/// <param name="context"></param>

/// <param name="culture"></param>

/// <param name="value">must be a built-in value type</param>

/// <returns></returns>

public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)

{

if (value is string)

{

return value;

}

return base.ConvertFrom(context, culture, value);

}

// Overrides the ConvertTo method of TypeConverter.

public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)

{

if (destinationType == typeof(string))

{

return value.ToString();

}

return base.ConvertTo(context, culture, value, destinationType);

}

}

//*********************** HOW TO READ AND WRITE IT **********************************

private void WriteConfig()

{

if (openTestConfigDialog.ShowDialog() != DialogResult.OK)

return;

string fullpath = openTestConfigDialog.FileName;

try

{

Configuration testConfig = ConfigurationManager.OpenExeConfiguration(fullpath);

System.Diagnostics.Debug.WriteLine(testConfig.FilePath);

if (testConfig.GetSection("testParameters") == null)

{

testConfig.Sections.Add("testParameters", new TestParamsSection());

}

TestParamsSection testParamsSection = testConfig.GetSection("testParameters") as TestParamsSection;

testParamsSection.TestParameters.Add(new ParamElement("param1", "System.String", "what u see is what u believe"));

testParamsSection.TestParameters.Add(new ParamElement("param2", "System.Int32", (int)678));

testParamsSection.TestParameters.Add(new ParamElement("param3", "System.Char", "F"));

testParamsSection.TestParameters.Add(new ParamElement("param4", "System.Boolean", true));

testParamsSection.TestParameters.Add(new ParamElement("param5", "System.Byte", (byte)0x12));

foreach (ParamElement element in testParamsSection.TestParameters)

{

dgvParameters.Rows.Add(new object[] { element.Name, element.Value});

}

foreach (DataGridViewRow row in dgvParameters.Rows)

{

System.Diagnostics.Debug.WriteLine(row.Cells["colValue"].Value.GetType().ToString());

}

dgvParameters.Refresh();

testConfig.SaveAs(fullpath, ConfigurationSaveMode.Full);

}

catch (ConfigurationErrorsException ex)

{

System.Diagnostics.Debug.WriteLine(ex.Message);

System.Exception innerEx = ex.InnerException;

if (innerEx != null)

System.Diagnostics.Debug.WriteLine("Inner exception type: " + innerEx.GetType().ToString() + ", message: " + innerEx.Message);

//throw;

}

}

private void ReadConfig()

{

if (openTestConfigDialog.ShowDialog() != DialogResult.OK)

return;

string fullpath = openTestConfigDialog.FileName;

try

{

Configuration testConfig = null;

// wrong way

//testConfig = ConfigurationManager.OpenExeConfiguration(fullpath);

// correct way

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();

fileMap.ExeConfigFilename = fullpath;

testConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

System.Diagnostics.Debug.WriteLine(testConfig.FilePath);

TestParamsSection testParamsSection = testConfig.GetSection("testParameters") as TestParamsSection;

foreach (ParamElement pe in testParamsSection.TestParameters)

System.Diagnostics.Debug.WriteLine(pe.Value.ToString());

}

catch (ConfigurationErrorsException ex)

{

System.Diagnostics.Debug.WriteLine(ex.Message);

System.Exception innerEx = ex.InnerException;

if (innerEx != null)

System.Diagnostics.Debug.WriteLine("Inner exception type: " + innerEx.GetType().ToString() + ", message: " + innerEx.Message);

//throw;

}

}






Re: .NET Base Class Library How to read values out of non-default configuration file?

Patrickje

I had the exact same problem!

So I wrote a quick and dirty parser

/// <summary>

/// Converts standard "NameValueSectionHandler" configuration Xml

/// to a NameValueCollection.

/// </summary>

/// <param name="xml">Xml to convert</param>

/// <returns>A valid name value collection object</returns>

/// <remarks>

/// No error handling.

/// </remarks>

private NameValueCollection GetNameValueCollectionFromXml(string xml)

{

NameValueCollection nvc = new NameValueCollection();

using (XmlReader reader = XmlReader.Create(new StringReader(xml)))

{

while (reader.Read())

{

if (reader.LocalName.ToLower() == "add")

{

if (reader.HasAttributes)

{

nvc.Add(reader.GetAttribute("key")

, reader.GetAttribute("value"));

}

}

}

reader.Close();

}

if (nvc.Count == 0)

{

nvc = null;

}

return nvc;

}

here's an example of how to call this.

NameValueCollection nvc = null;

System.Configuration.Configuration config =

ConfigurationManager.OpenMachineConfiguration();

ConfigurationSection cs = config.GetSection(sectionName);

if (cs != null)

{

// HACK:

// I was unable to get a valid NameValueCollection

// from the .net 2.0 ConfigurationSection!, so we'll just

// parse it for a collection ourselves.

nvc = GetNameValueCollectionFromXml(cs.SectionInformation.GetRawXml());

}