I have a C# app that has a custom section of configuration info in the App.config file. At this time, I am able to successfully load the custom info via code. However, I'm trying to load that same configuration info from a database as well. In an attempt to do this, I took a string of XML from my App.config file that I know is working. That string of XML looks like this:
<departments>
<department id="1" name="Sporting Goods">
<products>
<product name="Basketball" price="9.99">
<add key="Color" value="Orange" />
<add key="Brand" value="[BrandName]" />
</product>
</products>
</department>
</departments>
I am trying to deserialize this XML into C# objects. I've defined these objects like this:
Departments.cs
public class Departments : ConfigurationSection
{
private Departments() { }
[ConfigurationProperty("", IsRequired = false, IsKey = false, IsDefaultCollection = true)]
public DepartmentItemCollection Items
{
get
{
var items = base[""] as DepartmentItemCollection;
return items;
}
set { base["items"] = value; }
}
public static Departments Deserialize(string xml)
{
Departments departments = null;
var serializer = new XmlSerializer(typeof(Departments));
using (var reader = new StringReader(xml))
{
departments = (Departments)(serializer.Deserialize(reader));
}
return departments;
}
}
[ConfigurationCollection(typeof(Department), CollectionType = ConfigurationElementCollectionType.BasicMapAlternate)]
public class DepartmentItemCollection : ConfigurationElementCollection
{
private const string ItemPropertyName = "department";
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMapAlternate; }
}
protected override string ElementName
{
get { return ItemPropertyName; }
}
protected override bool IsElementName(string elementName)
{
return (elementName == ItemPropertyName);
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((Department)element).Name;
}
protected override ConfigurationElement CreateNewElement()
{
return new Department();
}
public override bool IsReadOnly()
{
return false;
}
}
Department.cs
public class Department : ConfigurationElement
{
public Department()
{ }
[ConfigurationProperty("id", IsRequired = false, IsKey = true)]
public int Id
{
get { return (int)(this["id"]); }
set { this["id"] = value; }
}
[ConfigurationProperty("name", IsRequired = true, IsKey = true, DefaultValue = "")]
public string Name
{
get { return (string)(this["name"]); }
set { this["name"] = value; }
}
[ConfigurationProperty("products", IsRequired = false, IsKey = false, IsDefaultCollection = false)]
public ProductCollection Products
{
get { return ((ProductCollection)(base["products"])); }
set { base["products"] = value; }
}
}
DepartmentProducts.cs
[ConfigurationCollection(typeof(Product), AddItemName = "product", CollectionType = ConfigurationElementCollectionType.BasicMapAlternate)]
public class ProductCollection: ConfigurationElementCollection
{
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMapAlternate; }
}
protected override string ElementName
{
get { return string.Empty; }
}
protected override bool IsElementName(string elementName)
{
return (elementName == "product");
}
protected override object GetElementKey(ConfigurationElement element)
{
return element;
}
protected override ConfigurationElement CreateNewElement()
{
return new Product();
}
protected override ConfigurationElement CreateNewElement(string elementName)
{
var product = new Product();
return product;
}
public override bool IsReadOnly()
{
return false;
}
}
DepartmentProduct.cs
public class Product : ConfigurationElement
{
public Product()
{ }
[ConfigurationProperty("name", IsRequired = true, IsKey = true, DefaultValue = "")]
public string Name
{
get { return (string)(this["name"]); }
set { this["name"] = value; }
}
[ConfigurationProperty("price", IsRequired = false)]
public decimal Price
{
get { return (decimal)(this["price"]); }
set { price["name"] = value; }
}
[ConfigurationProperty("", IsRequired = false, IsKey = false, IsDefaultCollection = true)]
public KeyValueConfigurationCollection Items
{
get
{
var items = base[""] as KeyValueConfigurationCollection;
return items;
}
set { base["items"] = value; }
}
}
When I pass the XML shown above to the Departments.Deserialize method, I receive the following error:
InvalidOperationException: You must implement a default accessor on System.Configuration.ConfigurationLockCollection because it inherits from ICollection.
How do I deserialize the XML I shared into the C# objects shared?
I had a similar issue in the past. While I couldn't figure out how to deal with the InvalidOperationException, I managed to get it working by directly tagging the class as IXmlSerializable
[XmlRoot("departments")]
public class Departments : ConfigurationSection, IXmlSerializable
{
//Your code here..
public XmlSchema GetSchema()
{
return this.GetSchema();
}
public void ReadXml(XmlReader reader)
{
this.DeserializeElement(reader, false);
}
public void WriteXml(XmlWriter writer)
{
this.SerializeElement(writer, false);
}
}
Related
So, I'm trying to make a custom configuration section for my app.config that will process the following pattern:
<domainSolutionSection>
<domainSolutionGroups>
<Group groupname="Legacy">
<add name="Old App #1"/>
<add name="Old App #2" />
</Group>
<Group groupname="Modern">
<add name="New App #1" />
<add name="New App #2" />
<add name="New App #3" />
</Group>
</domainSolutionGroups>
</domainSolutionSection>
I've spent all day trying to get this to work.
Right now, I'm getting an error:
System.Configuration.ConfigurationErrorsException: Unrecognized element 'add'.
Here are the classes in my DomainSolutionSection library:
public class DomainSolutionSection : ConfigurationSection
{
[ConfigurationProperty("domainSolutionGroups")]
public DomainSolutionGroupCollection DomainSolutionGroups
{
get
{
return (DomainSolutionGroupCollection) this["domainSolutionGroups"];
}
set
{
this["domainSolutionGroups"] = value;
}
}
}
[ConfigurationCollection(typeof(GroupConfigElement))]
public class DomainSolutionGroupCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new GroupConfigElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((GroupConfigElement)element).GroupName;
}
protected override string ElementName
{
get { return "Group"; }
}
protected override bool IsElementName(string elementName)
{
return !String.IsNullOrEmpty(elementName) && elementName == "Group";
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.BasicMap;
}
}
public GroupConfigElement this[int index]
{
get
{
return base.BaseGet(index) as GroupConfigElement;
}
}
public new GroupConfigElement this[string key]
{
get
{
return base.BaseGet(key) as GroupConfigElement;
}
}
}
public class GroupConfigElement : ConfigurationElement
{
[ConfigurationProperty("groupname", IsRequired = true, IsKey = true)]
public string GroupName
{
get { return (string)this["groupname"]; }
set { this["groupname"] = value; }
}
public PhraseCollection Phrases
{
get { return (PhraseCollection) base["Groups"]; }
}
}
[ConfigurationCollection(typeof(PhraseConfigElement), AddItemName = "add", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class PhraseCollection: ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new PhraseConfigElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((PhraseConfigElement)element).Name;
}
}
public class PhraseConfigElement: ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
}
Not finding any examples out there where "add" properties are used at this level of nesting, so obviously, I haven't "wired-up" the "Group" properly. Can anybody offer any guidance?
Thanks!
Apologies that this is not a direct answer to your question. I don't have the time to break down what you have done, but here is a similar example of something that I have done in the past, and which works. Perhaps there's something in here to help.
myconfig.config:
<?xml version="1.0"?>
<myconfig>
<moduleIPAccessRules>
<allowRules>
<add module="ModuleA" subnetIP="172.16.0.0" subnetMask="255.255.0.0" name="ModuleA intranet users" />
<add module="ModuleA" subnetIP="127.0.0.0" subnetMask="255.255.0.0" name="ModuleA local box" />
<add module="ModuleB" subnetIP="172.16.0.0" subnetMask="255.255.0.0" name="ModuleB intranet users" />
<add module="ModuleB" subnetIP="127.0.0.0" subnetMask="255.255.0.0" name="ModuleB local box" />
<add module="ModuleB" subnetIP="123.45.67.89" subnetMask="255.255.255.255" name="some remote machine" />
</allowRules>
</moduleIPAccessRules>
</myconfig>
Backing class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
namespace Myproject.Configuration
{
public class IPAccessSection : ConfigurationSection
{
public static IPAccessSection GetConfig()
{
return ConfigurationManager.GetSection("myconfig/moduleIPAccessRules") as IPAccessSection;
}
[ConfigurationProperty("allowRules")]
public AllowRuleCollection AllowRules
{
get { return this["allowRules"] as AllowRuleCollection; }
}
}
public class AllowRuleCollection : ConfigurationElementCollection
{
public AllowRule this[int index]
{
get
{
return base.BaseGet(index) as AllowRule;
}
set
{
if (base.BaseGet(index) != null)
base.BaseRemoveAt(index);
this.BaseAdd(index, value);
}
}
protected override ConfigurationElement CreateNewElement()
{
return new AllowRule();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((AllowRule)element).Name;
}
}
public class AllowRule : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return this["name"] as string; }
}
[ConfigurationProperty("module", IsRequired = true)]
public string Module
{
get { return this["module"] as string; }
}
[ConfigurationProperty("subnetIP", IsRequired = true)]
public string SubnetIP
{
get { return this["subnetIP"] as string; }
}
[ConfigurationProperty("subnetMask", IsRequired = true)]
public string SubnetMask
{
get { return this["subnetMask"] as string; }
}
}
}
Actually, I just figured out the answer about 10 minutes ago. And it's basically that I hadn't really "hooked up" the PhraseCollection to the GroupConfigElement properly... nor had I fully fleshed-out the PhraseCollection.:
public class GroupConfigElement : ConfigurationElement
{
[ConfigurationProperty("groupname", IsRequired = true, IsKey = true)]
public string GroupName
{
get { return (string)this["groupname"]; }
set { this["groupname"] = value; }
}
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
public PhraseCollection Phrases
{
get { return (PhraseCollection) base[""]; }
}
}
[ConfigurationCollection(typeof(PhraseConfigElement))]
public class PhraseCollection: ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new PhraseConfigElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((PhraseConfigElement)element).Name;
}
public PhraseConfigElement this[int index]
{
get
{
return base.BaseGet(index) as PhraseConfigElement;
}
}
public new PhraseConfigElement this[string key]
{
get
{
return base.BaseGet(key) as PhraseConfigElement;
}
}
}
public class PhraseConfigElement: ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
}
}
The key fixes were to the "Phrases" definition... and then I had to add those two public methods to the "PhraseCollection" definition.
Thanks!
I am getting Entry has already been added error when trying to use same title for SubModule. It is happening even though IsKey = false but still it is not allowing to enter duplicate Upload as Title
How can I fix this issue?
Here's my web.config
<SiteModules>
<Modules>
<MainModule title="MyUpload">
<SubModule title="Upload" page="/script/upload1" groups="group1" display="true" type="maker"></SubModule>
<SubModule title="Upload" page="/script/upload2" groups="group2" display="true" type="checker"></SubModule>
<SubModule title="SomeTitle1" page="/script/upload3" groups="group1" display="false"></SubModule>
</MainModule>
</Modules>
</SiteModules>
Here's my class
namespace MyClasses
{
public class SiteModules : ConfigurationSection
{
[ConfigurationProperty("Modules", IsDefaultCollection = false)]
public Modules Modules
{
get
{
Modules modulesConfigElement = (Modules)base["Modules"];
return modulesConfigElement;
}
}
}
public class Modules : ConfigurationElementCollection
{
public Modules()
{
AddElementName = "MainModule";
}
protected override ConfigurationElement CreateNewElement()
{
return new MainModule();
}
protected override Object GetElementKey(ConfigurationElement element)
{
return ((MainModule)element).Title;
}
}
public class MainModule : ConfigurationElementCollection
{
public MainModule()
{
AddElementName = "SubModule";
}
[ConfigurationProperty("title", IsRequired = true, IsKey = false)]
public string Title
{
get
{
return (string)this["title"];
}
set
{
this["title"] = value;
}
}
protected override ConfigurationElement CreateNewElement()
{
return new SubModule();
}
protected override Object GetElementKey(ConfigurationElement element)
{
return ((SubModule)element).Title;
}
}
public class SubModule : ConfigurationElement
{
[ConfigurationProperty("title", IsRequired = true, IsKey = false)]
public string Title
{
get
{
return (string)this["title"];
}
set
{
this["title"] = value;
}
}
[ConfigurationProperty("page", IsRequired = true)]
public string Page
{
get
{
return (string)this["page"];
}
set
{
this["page"] = value;
}
}
[ConfigurationProperty("groups", IsRequired = true)]
public string Groups
{
get
{
return (string)this["groups"];
}
set
{
this["groups"] = value;
}
}
[ConfigurationProperty("display", IsRequired = true)]
public string Display
{
get
{
return (string)this["display"];
}
set
{
this["display"] = value;
}
}
[ConfigurationProperty("type", IsRequired = false)]
public string Type
{
get
{
return (string)this["type"];
}
set
{
this["type"] = value;
}
}
}
}
The code which is throwing error is this:
SiteModules siteModules = (SiteModules)ConfigurationManager.GetSection("SiteModules");
Exception not related to IsKey attribute. Look on overrided method GetelementKey. In given case it return Title.. which is not unique.
protected override Object GetElementKey(ConfigurationElement element)
{
return ((MainModule)element).Title;
}
I have implemented custom section in web.config and want to save data there, in runtime debug when you check it contains all values that you put there and save without any exception. But web.config file didn't get updated at all.
I have following custom section in web.config
public class PrintersSection : ConfigurationSection
{
[ConfigurationProperty("PrintForm", Options = ConfigurationPropertyOptions.IsRequired)]
public PrintFormElement PrintForm
{
get
{
return (PrintFormElement)this["PrintForm"];
}
set { this["PrintForm"] = value; }
}
[ConfigurationProperty("Printers", Options = ConfigurationPropertyOptions.IsRequired)]
public PrintersCollection Printers
{
get
{
return (PrintersCollection)this["Printers"];
}
set { this["Printers"] = value; }
}
public override bool IsReadOnly()
{
return false;
}
}
public class PrintFormElement : ConfigurationElement
{
[ConfigurationProperty("xmlPath")]
public string XmlPath
{
get
{
return (string)base["xmlPath"];
}
set { base["xmlPath"] = value; }
}
[ConfigurationProperty("formName")]
public string FormName
{
get
{
return (string)base["formName"];
}
set { base["formName"] = value; }
}
[ConfigurationProperty("sdateFormat")]
public string SDateFormat
{
get
{
return (string)base["sdateFormat"];
}
set { base["sdateFormat"] = value; }
}
[ConfigurationProperty("createOnTechpadMarkAsComplete")]
public bool CreateOnTechpadMarkAsComplete
{
get
{
return (bool)base["createOnTechpadMarkAsComplete"];
}
set { base["createOnTechpadMarkAsComplete"] = value; }
}
[ConfigurationProperty("createOnSurveySubmit")]
public bool CreateOnSurveySubmit
{
get
{
return (bool)base["createOnSurveySubmit"];
}
set { base["createOnSurveySubmit"] = value; }
}
public override bool IsReadOnly()
{
return false;
}
}
[ConfigurationCollection(typeof(PrinterElement), AddItemName = "printer", CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)]
public class PrintersCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new PrinterElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return ((PrinterElement)element).Location;
}
[ConfigurationProperty("default", IsRequired = false)]
public string Default
{
get
{
return (string)base["default"];
}
set { base["default"] = value; }
}
public new PrinterElement this[string location]
{
get { return base.BaseGet(location) as PrinterElement; }
}
public void Add(PrinterElement element)
{
base.BaseAdd(element);
}
public void Clear()
{
base.BaseClear();
}
public override bool IsReadOnly()
{
return false;
}
}
public class PrinterElement : ConfigurationElement
{
[ConfigurationProperty("location", IsRequired = true, IsKey = true)]
public string Location
{
get
{
return (string)base["location"];
}
set { base["location"] = value; }
}
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get
{
return (string)base["name"];
}
set { base["name"] = value; }
}
public override bool IsReadOnly()
{
return false;
}
}
Here how it looks in web.config:
<printers>
<PrintForm xmlPath="H:\Temp\print3.txt" formName="test-form"
sdateFormat="MM-dd-yyyy" createOnTechpadMarkAsComplete="true"
createOnSurveySubmit="true" />
<Printers default="PrinterA">
<clear />
<printer location="1" name="PrinterA" />
<printer location="2" name="PrinterB" />
</Printers>
</printers>
This is how I editing it:
webConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
var printXmlConfig = (PrintersSection)ConfigurationManager.GetSection("printers");
printXmlConfig.PrintForm.XmlPath = model.PrintXMLPath;
printXmlConfig.PrintForm.FormName = model.PrintXMLFormName;
printXmlConfig.Printers.Default = model.PrintXMLPrinterName;
printXmlConfig.PrintForm.SDateFormat = model.PrintXMLSDateFormat;
printXmlConfig.PrintForm.CreateOnTechpadMarkAsComplete = model.PrintXMLCreateOnTechpadMarkAsComplete;
printXmlConfig.PrintForm.CreateOnSurveySubmit = model.PrintXMLCreateOnSurveySubmit;
printXmlConfig.Printers.Clear();
model.PrinterPerLocation.ForEach(p => printXmlConfig.Printers.Add(new PrinterElement { Location = p.Key, Name = p.Value}));
webConfig.Save();
But nothing updates in web.config, what I am doing wrong here?
Try
printXmlConfig.SectionInformation.ForceSave = true;
or
webConfig.SectionInformation.ForceSave = true;
before
webConfig.Save(ConfigurationSaveMode.Full);
I'm creating a custom configuration section but I keep getting a Attribute Not Recognized error when trying to get the section.
I'm pretty sure it's some dumb typo - hopefully someone here can spot it.
Code:
<configSections>
<section name="ClientFilterSettings" type="ESPDB.Config.ClientFilterSettings, ESPDB"/>
</configSections>
<ClientFilterSettings>
<AllowedIPs>
<IPAddress IP="255.255.255.255"/>
</AllowedIPs>
</ClientFilterSettings>
Section:
namespace ESPDB.Config
{
public class ClientFilterSettings : ConfigurationSection
{
private static ClientFilterSettings _settings =
ConfigurationManager.GetSection(typeof(ClientFilterSettings).Name) as ClientFilterSettings
/*?? new ClientFilterSettings()*/;
private const string _allowedIPs = "AllowedIPs";
public static ClientFilterSettings Settings
{
get { return _settings; }
}
[ConfigurationProperty(_allowedIPs, IsRequired = true)]
[ConfigurationCollection(typeof(IPAddressCollection))]
public IPAddressCollection AllowedIPs
{
get { return (IPAddressCollection)this[_allowedIPs]; }
set { this[_allowedIPs] = value; }
}
}
}
Collection:
namespace ESPDB.Config
{
public class IPAddressCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new IPAddressCollection();
}
protected override object GetElementKey(ConfigurationElement element)
{
return (element as IPAddressElement).IP;
}
protected override string ElementName
{
get { return "IPAddress"; }
}
public IPAddressElement this[int index]
{
get
{
return base.BaseGet(index) as IPAddressElement;
}
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
public new IPAddressElement this[string responseString]
{
get { return (IPAddressElement)BaseGet(responseString); }
set
{
if (BaseGet(responseString) != null)
{
BaseRemoveAt(BaseIndexOf(BaseGet(responseString)));
}
BaseAdd(value);
}
}
}
}
Element
namespace ESPDB.Config
{
public class IPAddressElement : ConfigurationElement
{
private const string _ip = "IP";
[ConfigurationProperty(_ip, IsKey = true, IsRequired = true)]
public string IP
{
get { return this[_ip] as string; }
set { this[_ip] = value; }
}
}
}
There are multiple problems in your code.
1). You are recursively creating objects of ClientFilterSettings. Remove the following code, its not required.
private static ClientFilterSettings _settings =
ConfigurationManager.GetSection(typeof(ClientFilterSettings).Name) as ClientFilterSettings /*?? new ClientFilterSettings()*/;
public static ClientFilterSettings Settings
{
get { return _settings; }
}
2). Change the attribute from
[ConfigurationCollection(typeof(IPAddressCollection))]
TO
[ConfigurationCollection(typeof(IPAddressElement), AddItemName = "IPAddress", CollectionType = ConfigurationElementCollectionType.BasicMap)]
3). You are creating collection object within a collection. Modify the code below
return new IPAddressCollection();
WITH
return new IPAddressElement();
I'm having trouble getting a custom config section to work. It's some code I got from the web in an effort to try to understand this area a little better and enable me to get to where I want to ultimatly be, my own custom config section.
The error I get when I run the code in a console app is
'
Unrecognized attribute 'extension'. Note that attribute names are case-sensitive.'
The code in the main app to get things going is
var conf = ConfigurationManager.GetSection("uploadDirector");
and this is where the exception appears.
This is the config section I am hoping/trying to achieve
<AuthorisedClients>
<AuthorisedClient name="Client">
<Queue id="1" />
<Queue id="7" />
</AuthorisedClient>
<AuthorisedClient name="Client2">
<Queue id="3" />
<Queue id="4" />
</AuthorisedClient>
</AuthorisedClients>
Here's the code I have got from the web
.config file
<uploadDirector>
<filegroup name="documents" defaultDirectory="/documents/">
<clear/>
<add extension="pdf" mime="application/pdf" maxsize="100"/>
<add extension="doc" mime="application/word" maxsize="500"/>
</filegroup>
<filegroup name="images">
<clear/>
<add extension="gif" mime="image/gif" maxsize="100"/>
</filegroup>
</uploadDirector>
UploadDirectorConfigSection.cs
public class UploadDirectorConfigSection : ConfigurationSection {
private string _rootPath;
public UploadDirectorConfigSection() {
}
[ConfigurationProperty("rootpath", DefaultValue="/", IsRequired=false, IsKey=false)]
[StringValidator(InvalidCharacters=#"~!.##$%^&*()[]{};'\|\\")]
public string RootPath {
get { return _rootPath; }
set { _rootPath = value; }
}
[ConfigurationProperty("", IsRequired = true, IsKey = false, IsDefaultCollection = true)]
public FileGroupCollection FileGroups {
get { return (FileGroupCollection) base[""]; }
set { base[""] = value; }
}
}
FileGroupCollection.cs
public class FileGroupCollection : ConfigurationElementCollection {
protected override ConfigurationElement CreateNewElement() {
return new FileGroupElement();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((FileGroupElement) element).Name;
}
public override ConfigurationElementCollectionType CollectionType {
get {
return ConfigurationElementCollectionType.BasicMap;
}
}
protected override string ElementName {
get {
return "filegroup";
}
}
protected override bool IsElementName(string elementName) {
if (string.IsNullOrWhiteSpace(elementName) || elementName != "filegroup")
return false;
return true;
}
public FileGroupElement this[int index] {
get { return (FileGroupElement) BaseGet(index); }
set {
if(BaseGet(index) != null)
BaseRemoveAt(index);
BaseAdd(index, value);
}
}
}
FileGroupElement.cs
public class FileGroupElement : ConfigurationElement {
[ConfigurationProperty("name", IsKey=true, IsRequired = true)]
[StringValidator(InvalidCharacters = #" ~.!##$%^&*()[]{}/;'""|\")]
public string Name {
get { return (string) base["name"]; }
set { base["name"] = value; }
}
[ConfigurationProperty("defaultDirectory", DefaultValue = ".")]
public string DefaultDirectory {
get { return (string) base["Path"]; }
set { base["Path"] = value; }
}
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
public FileInfoCollection Files {
get { return (FileInfoCollection) base[""]; }
}
}
FileInfoCollection.cs
public class FileInfoCollection : ConfigurationElementCollection {
protected override ConfigurationElement CreateNewElement() {
return new FileInfoCollection();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((FileInfoElement) element).Extension;
}
}
FileInfoElement.cs
public class FileInfoElement : ConfigurationElement {
public FileInfoElement() {
Extension = "txt";
Mime = "text/plain";
MaxSize = 0;
}
[ConfigurationProperty("extension", IsKey = true, IsRequired = true)]
public string Extension {
get { return (string)base["extension"]; }
set { base["extension"] = value; }
}
[ConfigurationProperty("mime", DefaultValue = "text/plain")]
public string Mime {
get { return (string) base["mime"]; }
set { base["mime"] = value; }
}
[ConfigurationProperty("maxsize", DefaultValue = 0)]
public int MaxSize {
get { return (int) base["maxsize"]; }
set { base["maxsize"] = value; }
}
}
In your definition of FileInfoCollection in the method CreateNewElement you create FileInfoCollection which is wrong. Overridden CreateNewElement should return new collection element, not the new collection:
public class FileInfoCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new FileInfoElement();
}
protected override object GetElementKey (ConfigurationElement element)
{
return ((FileInfoElement)element).Extension;
}
}
Regarding your desired configuration, probably the simplest implementation will look like:
public class AuthorisedClientsSection : ConfigurationSection {
[ConfigurationProperty("", IsDefaultCollection = true)]
public AuthorisedClientElementCollection Elements {
get { return (AuthorisedClientElementCollection)base[""];}
}
}
public class AuthorisedClientElementCollection : ConfigurationElementCollection {
const string ELEMENT_NAME = "AuthorisedClient";
public override ConfigurationElementCollectionType CollectionType {
get { return ConfigurationElementCollectionType.BasicMap; }
}
protected override string ElementName {
get { return ELEMENT_NAME; }
}
protected override ConfigurationElement CreateNewElement() {
return new AuthorisedClientElement();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((AuthorisedClientElement)element).Name;
}
}
public class AuthorisedClientElement : ConfigurationElement {
const string NAME = "name";
[ConfigurationProperty(NAME, IsRequired = true)]
public string Name {
get { return (string)base[NAME]; }
}
[ConfigurationProperty("", IsDefaultCollection = true)]
public QueueElementCollection Elements {
get { return (QueueElementCollection)base[""]; }
}
}
public class QueueElementCollection : ConfigurationElementCollection {
const string ELEMENT_NAME = "Queue";
public override ConfigurationElementCollectionType CollectionType {
get { return ConfigurationElementCollectionType.BasicMap; }
}
protected override string ElementName {
get { return ELEMENT_NAME; }
}
protected override ConfigurationElement CreateNewElement() {
return new QueueElement();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((QueueElement)element).Id;
}
}
public class QueueElement : ConfigurationElement {
const string ID = "id";
[ConfigurationProperty(ID, IsRequired = true)]
public int Id {
get { return (int)base[ID]; }
}
}
And the test:
var authorisedClientsSection = ConfigurationManager.GetSection("AuthorisedClients")
as AuthorisedClientsSection;
foreach (AuthorisedClientElement client in authorisedClientsSection.Elements) {
Console.WriteLine("Client: {0}", client.Name);
foreach (QueueElement queue in client.Elements) {
Console.WriteLine("\tQueue: {0}", queue.Id);
}
}