2007-07-27

Custom Sections in app.config

Sometime you need store application configuration in a config file and .Net gives you tools to do it.
You must create a app.config file to store this data, this file must be copied to application runtime directory renamed like this: PathCopy.exe.config (I asumed that I compile my application and generates a PathCopy.exe file).

I my case I want to store a list of urls in the config file, like this:

-- app.config --
<configuration>
<configSections>
<section name="PathToCopy" type="PathCopy.PathCopyConfigurationSection, PathCopy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true"/>
</configSections>
<PathToCopy>
<urls>
<add source="C:\pathSource1" target="C:\pathTarget1" lastcopy="01/12/2007 14:59:25" />
<add source="C:\pathSource2" target="C:\pathTarget2" lastcopy="01/12/2007 14:59:25" />
<add source="C:\pathSource3" target="C:\pathTarget3" lastcopy="01/12/2007 14:59:25" />
</urls>
</PathToCopy>

</configuration>
-- end app.config

Read this config file is as easy as this:

PathCopyConfigurationSection key = (PathCopyConfigurationSection)System.Configuration.ConfigurationManager.GetSection("PathToCopy");

Of course you must define the classes PathCopyConfigurationSection, PathCopyConfigurationElementCollection, PathCopyConfigurationElement first.

And you can use the read section (key) easily

foreach (PathCopyConfigurationElement key in keySection.Urls)
{
Console.WriteLine ("Coping path {0} to {1}", key.Source, key.Target);
}

As you see you can define a ConfigurationElement property from app.config element ()

[ConfigurationProperty("source")]
public string Source
{
get
{
return (string)this["source"];
}
set
{
this["source"] = value;
}
}

To configure the collection you must create the property in the ConfigurationSection class
[ConfigurationProperty("urls",
IsDefaultCollection = false)]
public PathCopyConfigurationElementCollection Urls
{
get
{
PathCopyConfigurationElementCollection urlsCollection = (PathCopyConfigurationElementCollection)base["urls"];
return urlsCollection;
}
}

And PathCopyConfigurationElementCollection only is defined to avoid casts of PathCopyConfigurationElement.

Of course, remenber add reference to System.Configuration.dll



-- code --
using System;
using System.Configuration;
namespace PathCopy {
public void Main()
{
PathCopyConfigurationSection key = (PathCopyConfigurationSection)System.Configuration.ConfigurationManager.GetSection("PathToCopy");
foreach (PathCopyConfigurationElement key in keySection.Urls)
{
Console.WriteLine ("Coping path {0} to {1}", key.Source, key.Target);
}
}

public class PathCopyConfigurationElement : ConfigurationElement
{
#region Properties
[ConfigurationProperty("source")]
public string Source
{
get
{
return (string)this["source"];
}
set
{
this["source"] = value;
}
}
[ConfigurationProperty("target")]
public string Target
{
get
{
return (string)this["target"];
}
set
{
this["target"] = value;
}
}
[ConfigurationProperty("lastcopy")]
public DateTime LastCopy
{
get
{
return (DateTime)this["lastcopy"];
}
set
{
this["lastcopy"] = value;
}
}

#endregion
#region Constructors
public PathCopyConfigurationElement()
{
}
#endregion

}

public class PathCopyConfigurationElementCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new PathCopyConfigurationElement();
}

protected override object GetElementKey(ConfigurationElement element)
{
object key = null;
PathCopyConfigurationElement myElement = element as PathCopyConfigurationElement;
if (myElement != null)
{
key = myElement.Source;
}
return key;

}
}


public class PathCopyConfigurationSection : ConfigurationSection
{

#region Properties
[ConfigurationProperty("urls",
IsDefaultCollection = false)]
public PathCopyConfigurationElementCollection Urls
{
get
{
PathCopyConfigurationElementCollection urlsCollection = (PathCopyConfigurationElementCollection)base["urls"];
return urlsCollection;
}
}

#endregion
#region Constructors
public PathCopyConfigurationSection()
{
}
#endregion
}
}
-- end code --

-- console out --
Coping path C:\pathSource1 to C:\pathTarget1
Coping path C:\pathSource2 to C:\pathTarget2
Coping path C:\pathSource3 to C:\pathTarget3
-- end console out --