If MyApp.PluginsConfiguration is a ConfigurationSection, then you can define a new Class that inherits from ConfigurationElementCollection and make the new class a ConfigurationProperty of MyApp.PluginsConfiguration
Check this article for some in-depth info about those types. I also blogged about having nested properties, but not specifically for collections.
Edit: Here with some code. Given is this bit in the web.config:
<configSections>
<section name="plugins"
type="WebApplication1.PluginsConfiguration, WebApplication1"/>
</configSections>
<plugins>
<use assembly="MyApp.Plugin1.dll"/>
<use assembly="MyApp.Plugin2.dll"/>
</plugins>
Here is are the classes to make that happen. Note that there maybe NullReferenceExceptions that would need to be handled.
namespace WebApplication1
{
public class PluginsConfiguration : ConfigurationSection
{
private static ConfigurationPropertyCollection properties;
private static ConfigurationProperty propPlugins;
static PluginsConfiguration()
{
propPlugins = new ConfigurationProperty(null, typeof(PluginsElementCollection),
null,
ConfigurationPropertyOptions.IsDefaultCollection);
properties = new ConfigurationPropertyCollection { propPlugins };
}
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public PluginsElementCollection Plugins
{
get
{
return this[propPlugins] as PluginsElementCollection;
}
}
}
public class PluginsElementCollection : ConfigurationElementCollection
{
public PluginsElementCollection()
{
properties = new ConfigurationPropertyCollection();
}
private static ConfigurationPropertyCollection properties;
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.BasicMap;
}
}
protected override string ElementName
{
get
{
return "use";
}
}
protected override ConfigurationElement CreateNewElement()
{
return new PluginsElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
var elm = element as PluginsElement;
if (elm == null) throw new ArgumentNullException();
return elm.AssemblyName;
}
}
public class PluginsElement : ConfigurationElement
{
private static ConfigurationPropertyCollection properties;
private static ConfigurationProperty propAssembly;
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public PluginsElement()
{
propAssembly = new ConfigurationProperty("assembly", typeof(string),
null,
ConfigurationPropertyOptions.IsKey);
properties = new ConfigurationPropertyCollection { propAssembly };
}
public PluginsElement(string assemblyName)
: this()
{
AssemblyName = assemblyName;
}
public string AssemblyName
{
get
{
return this[propAssembly] as string;
}
set
{
this[propAssembly] = value;
}
}
}
}
And to access it, this code snippet should help:
var cfg = WebConfigurationManager.GetWebApplicationSection("plugins") as PluginsConfiguration;
var sb = new StringBuilder();
foreach(PluginsElement elem in cfg.Plugins)
{
sb.AppendFormat("{0}<br/>", elem.AssemblyName);
}
testLabel.Text = sb.ToString();
Basically we have a ConfigurationSection that handles the plugins-element. In this, we specify a ConfigurationElementCollection property and declare it as the Default Collection (you could in theory have multiple different collections under one root node).
PluginsElementCollection implements the ConfigurationElementCollection. ElementName has to be the name of the tag, in our case "use". Also, GetElementKey needs to be overridden and should return an attribute that is unique among the entries.
PluginsElement then implements a single use tag. We only define one property: AssemblyName, which is mapped to the assembly-attribute.
I don't claim to fully understand all of this (Especially ConfigurationElementCollection and it's various BaseAdd, BaseGet etc. properties are not really explored here), but I can claim that this works :)
Also, It doesn't use any attributes. I hate Attributes - luckily, all these attributes can be converted to proper code. You could use one or the other (or both).