Scott Dorman

ephemeral segment

  Home  |   Contact  |   Syndication    |   Login
  608 Posts | 11 Stories | 900 Comments | 51 Trackbacks

News


Post Categories

Image Galleries


Microsoft Store


Creative Commons License



Locations of visitors to this page

Subscribers to this feed

TwitterCounter for @sdorman

View blog authority

Add to Technorati Favorites

Windows Live Alerts

AddThis Social Bookmark Button

LinkedIn profile

Community Credit profile

The Code Project

Follow me on Twitter

Get Free Shots from Snap.com

Community Credit Hall of Fame

Get Feedghost

Xobni outlook add-in for your inbox



Support This Site

Tag Cloud


Article Categories

Archives

Post Categories

Image Galleries

I spent most of yesterday trying to figure out how to make use of a NameValueCollection in a .NET configuration file. After wasting almost the entire night fighting with this problem, I thought I would let everyone know that it is possible, and easier than you might think. (By the way, this was a clear case of working too long on the problem. After a good nights sleep, I solved this in under 5 minutes.)

At this point you might wonder why this was so difficult. The largest and most significant problem is the fact that NameValueCollection isn't serializable (KB 814187). The reason for this is that NameValueCollection doesn't implement ICollection but extends NameObjectCollectionBase instead. The recommended solution is to use a SoapFormatter to serialize and deserialize the collection. While using the SoapFormatter does work, it seemed like a very complex solution for a seemingly simple problem.

Not wanting to over-engineer my solution, I started searching the web for alternatives. I found several newsgroup postings that all said to use the SoapFormatter since that was the recommended solution and the only way to go. Not having drunk too much blue kool-aid, I kept searching. That search turned up an article by Keyvan Nayyeri that shows how to created a serializable NameValueCollection. This approach was intriguing and certainly seemed to be a more useful solution than using the SoapFormatter, but again it seemed like a lot of work.

Keep in mind, all I wanted to be able to do in the configuration file was to create a section that looked like this:

   1: <copyFiles>
   2:   <add name="C:\Windows" value="*.dll"/>
   3:   <add name="C:\Temp"/>
   4: </copyFiles>

Continuing the search, I thought I found my answer. I stumbled across an article (".NET How To Create and Use Custom Name-Value Config Sections") that shows how to do this in 4 simple steps. Reading through the article, I realized that it is written using the the .NET 1.0 and 1.1 ConfigurationSettings, which is provided for backwards compatibility only. Since the application I'm working on is .NET 3.5 and taking advantage of many of the new language features, I wanted to ensure that I wasn't using any deprecated classes.

This is where I started running into additional problems. It seems that Microsoft provides a NameValueSectionHandler, which the article makes us of. The problem is that NameValueSectionHandler is architected following the .NET 1.0/1.1 model and implements the System.Configuration.IConfigurationSectionHandler interface. This is great if you want to use the deprecated ConfigurationSettings class; if you want to use the recommended System.Configuration.ConfigurationManager or System.Web.Configuration.WebConfigurationManager classes you are out of luck. They will only work with a class that derives from ConfigurationSection.

So, after all this I thought I was out of luck and would need to write my own configuration section handler. (Remember, this was about 1:00 AM.) After sleeping on it, I realized that there was a much simpler way. Along with the NameValueSectionHandler, Microsoft also implemented NameValueConfigurationCollection and NameValueConfigurationElement, which derive from the appropriate configuration classes to be used by the ConfigurationManager. After seeing that, I realized that all I needed to do was implement a NameValueSection which derives from ConfigurationSection.

This is where the solution becomes easy. In it's simplest most form, the NameValueSection looks like this:

   1: public class NameValueSection : ConfigurationSection
   2: {
   3:     [ConfigurationProperty("", IsDefaultCollection = true)]
   4:     public NameValueConfigurationCollection Settings
   5:     {
   6:         get
   7:         {
   8:             return (NameValueConfigurationCollection)base[""];
   9:         }
  10:     }
  11: }

As you can see, this is pretty simple. In order to use it, you declare the section in your app.config file:

   1: <sectionGroup name="customSettings">
   2:    <section name="copyFiles" type="NameValueSection, CustomConfiguration"/>
   3: </sectionGroup>
   4: <copyFiles>
   5:    <add name="C:\Windows" value="*.dll"/>
   6:    <add name="C:\Temp"/>
   7: </copyFiles>

To access this configuration section in code, you simply need to do this:

   1: NameValueSection nameValueSection = ConfigurationManager.GetSection("copyFiles") as NameValueSection;
   2: if (nameValueSection != null)
   3: {
   4:     NameValueConfigurationCollection settings = nameValueSection.Settings;
   5:     foreach (string key in settings.AllKeys)
   6:     {
   7:         Console.WriteLine(settings[key].Name + ": " + settings[key].Value);
   8:     }
   9: }

This is about as simple as it gets. Even though you aren't actually using the real NameValueCollection you are using the NameValueConfigurationCollection, which has almost identical behavior. This is the solution that I finally ended up implementing and it works great. As you can see, with a minimal amount of effort you are now able to use a NameValueCollection in your configuration files.

posted on Sunday, March 16, 2008 8:00 PM

Feedback

# re: NameValueCollection and .NET Configuration Files 4/30/2008 6:55 AM Sébastien Gillet
For the above sample to build I had to change the following (VS 2008):
1) encapsulate the copyFiles section into a customSettings section like:
<customSettings>
<copyFiles>
<add name="C:\Windows" value="*.dll"/>
<add name="C:\Temp"/>
</copyFiles>
</customSettings>

2) Also add this parent section into the GetSection call like in:
= ConfigurationManager.GetSection("customSettings/copyFiles")

# re: NameValueCollection and .NET Configuration Files 10/3/2008 5:16 PM Ben
when i ran above sample i got the error
"An error occurred creating the configuration section handler for customSettings/copyFiles: Could not load file or assembly 'CustomConfiguration' or one of its dependencies. The system cannot find the file specified." Any idea?

Thanks,

# re: NameValueCollection and .NET Configuration Files 11/15/2008 10:21 PM Scott
Ben, You need to ensure that System.Configuration is listed as a reference in your project.

# re: NameValueCollection and .NET Configuration Files 1/28/2009 11:03 AM UTCD
Why not use a custom AppSettingsSection?

<configSections>
<sectionGroup name="customSettings">
<section name="copyFiles" type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</sectionGroup>
</configSections>
<customSettings>
<copyFiles>
<add key="C:\Windows" value="*.dll"/>
<add key="C:\Temp"/>
</copyFiles>
</customSettings>

NameValueCollection settings = ConfigurationManager.GetSection("customSettings/copyFiles") as NameValueCollection;
if (settings != null)
{
foreach (string key in settings.AllKeys)
{
Response.Write(key + ": " + settings[key] + "<br />");
}
}

# re: NameValueCollection and .NET Configuration Files 2/6/2009 10:33 AM Naresh
NameValueCollection settings = ConfigurationManager.GetSection("customSettings/copyFiles") as NameValueCollection;

I was using above logic and encountered an error "Cannot load the config file".

# re: NameValueCollection and .NET Configuration Files 11/22/2009 11:15 PM Jingle
Thank you! I have made it.

# re: NameValueCollection and .NET Configuration Files 4/30/2010 2:35 PM Rich Jardine
Scott,
Great solution! I am converting an app that uses extensive registry entries to use a custom config file. I couldn't access a NameValue Collection from the custom configuration until I found your solution.
Thank you!

# re: NameValueCollection and .NET Configuration Files 9/15/2011 8:20 AM kique net
I try use this in my Addin VS, load a config file and I get this error:


//System.Configuration.ConfigurationErrorsException: Unrecognized attribute 'key'. Note that attribute names are case-sensitive. (E:\TFS\pro\RealeTeam\Main\Public\RealeDevelopment\RealeAddIn\bin\Debug\RealeAddIn.dll.config line 10)
// NameValueSection nameValueSection = config.GetSection("ImpersonationSettings") as NameValueSection;

THX

# re: NameValueCollection and .NET Configuration Files 9/26/2011 9:26 AM stenly
very good example! thanks

# re: NameValueCollection and .NET Configuration Files 11/4/2011 5:59 PM David
Great post ... you nailed it!!! I spent the better part of 3 days browsing the net, finding many of the same solutions you found in your search. I find MSDN to be pretty good as a reference tool, but pretty lacking in the "show me how to ..." department. Finally, I came across your solution. Thanks so much ... it was a huge help.

# re: NameValueCollection and .NET Configuration Files 1/17/2012 4:57 PM Jim
Excellent post by Scott! I was struggling with a similar problem and he helped me to solve it. But my issue requires adding new NameValue pair at run time. Here is how I do it.

Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

NameValueSection section = config.GetSection("customSettings/copyFiles") as NameValueSection;

if (section != null)
{
section.Add("Name", "Value");

config.Save(ConfigurationSaveMode.Modified);
}

public class NameValueSection : ConfigurationSection
{
[ConfigurationProperty("", IsDefaultCollection = true)]
public NameValueConfigurationCollection Settings
{
get
{
return (NameValueConfigurationCollection)base[""];
}
}

public void Add(string name, string value)
{
Settings.Add(new NameValueConfigurationElement(name, value));
}
}


# re: NameValueCollection and .NET Configuration Files 3/3/2013 10:48 AM ALH
This absolutely doesn't work for me. My code is identical and I am constantly getting the following error no matter what I change in the app.config.

Could not load file or assembly 'CustomConfiguration' or one of its dependencies. The system cannot find the file specified.

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: