I have the following bits in App.config for a .NET 3.5 Windows Service:
<configSections>
<section name="ConfigurationServiceSection" type="SomeApp.Framework.Configuration.ConfigurationServiceSection, SomeApp.Framework"/>
</configSections>
<ConfigurationServiceSection configSource="ConfigSections\configurationServiceSection.config" />
I've got this in configurationServiceSection.config:
<ConfigurationServiceSection>
<ConfigurationServices>
<ConfigurationService name="LocalConfig" host="localhost" port="40001" location="LON"/>
</ConfigurationServices>
</ConfigurationServiceSection>
And here's the code:
using System.Configuration;
namespace SomeApp.Framework.Configuration
{
public sealed class ConfigurationServiceSection : ConfigurationSection
{
[ConfigurationProperty("ConfigurationServices", IsDefaultCollection = true, IsRequired = true)]
[ConfigurationCollection(typeof(ConfigurationServices))]
public ConfigurationServices ConfigurationServices
{
get
{
return (ConfigurationServices)base["ConfigurationServices"];
}
}
}
public sealed class ConfigurationServices : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new ConfigurationService();
}
protected override object GetElementKey(ConfigurationElement element)
{
ConfigurationService configService = (ConfigurationService) element;
return configService.Name;
}
}
public sealed class ConfigurationService : ConfigurationElement
{
/// <summary>
/// name
/// </summary>
[ConfigurationProperty("name", IsKey = true, IsRequired = true)]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
/// <summary>
/// host
/// </summary>
[ConfigurationProperty("host", IsKey = false, IsRequired = true)]
public string Host
{
get { return (string)this["host"]; }
set { this["host"] = value; }
}
/// <summary>
/// port
/// </summary>
[ConfigurationProperty("port", IsKey = false, IsRequired = true)]
public string Port
{
get { return (string)this["port"]; }
set { this["port"] = value; }
}
/// <summary>
/// location
/// </summary>
[ConfigurationProperty("location", IsKey = false, IsRequired = true)]
public string Location
{
get { return (string)this["location"]; }
set { this["location"] = value; }
}
}
}
When I try to access the config with the following:
var configurationServiceSection = (ConfigurationServiceSection)configuration.GetSection("ConfigurationServiceSection");
I get this exception:
Unrecognized element 'ConfigurationService'. (C:\Code\branches\ConfigurationService\SomeApp\Src\ConfigService\SomeApp.ConfigService.WindowsService\bin\Debug\ConfigSections\configurationServiceSection.config line 3)
Everything looks in order to me?
Any ideas please? Thanks.
Ok got to the bottom of this:
I added 'AddItemName' to the ConfigurationServiceSection class, as per below:
public sealed class ConfigurationServiceSection : ConfigurationSection
{
[ConfigurationProperty("ConfigurationServices", IsDefaultCollection = true, IsRequired = true)]
[ConfigurationCollection(typeof(ConfigurationServices), AddItemName = "ConfigurationService")]
public ConfigurationServices ConfigurationServices
{
get
{
return (ConfigurationServices)base["ConfigurationServices"];
}
}
}
Another alternative was to override the CollectionType and ElementName properties, as per below:
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
protected override string ElementName
{
get { return "ConfigurationService"; }
}
Related
I have an xml as shown below and want to pass it as a response from wcf service.What i did is, i used Visual studio to generate c# classes from xml and then deserilize the xml with the classes generated from VS.Data is coming in Soap UI from WCF service but when i click validate in soap ui, it is throwing error
EDIT on 250320
Finally i reached to single error like
line 17: Invalid xsi:type qname: 'c:string' in element SITE_NAME#http://schemas.datacontract.org/2004/07/ITSM_GIS_NRMIntegration.BusinessObjects
c# code
namespace ITSM_GIS_NRMIntegration
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class GisItsmService : IGisItsmService
{
Datatable dtcustomerSiteDtls = dtcustomerSiteDtls.AsEnumerable()
.OrderBy(x => x.Field<string>("CBCM_PARTY_ID"))
.ThenBy(x => x.Field<string>("CBCM_PARTY_NAME"))
.ThenBy(x => x.Field<string>("SERVICE"))
.ThenBy(x => x.Field<string>("SITENAME"))
.ThenBy(x => x.Field<string>("NODENAME"))
.CopyToDataTable();
XElement allSites = doc.Root;
foreach (var idGroup in dtcustomerSiteDtls.AsEnumerable().GroupBy(x => x.Field<string>("CBCM_PARTY_ID")))
{
XElement siteNode = new XElement("PARTY_SITE_NODES");
allSites.Add(siteNode);
siteNode.Add(new XElement("CBCM_PARTY_ID", idGroup.Key));
siteNode.Add(new XElement("CBCM_PARTY_NAME", idGroup.First().Field<string>("CBCM_PARTY_NAME")));
DataTable dtfilter = dtcustomerSiteDtls.Select("CBCM_PARTY_ID = '" + idGroup.Key.ToString() + "'").CopyToDataTable();
foreach (var service in dtfilter.AsEnumerable().GroupBy(x => x.Field<string>("SERVICE")))
{
XElement partyServices = new XElement("PARTY_SERVICES");
siteNode.Add(partyServices);
partyServices.Add(new XElement("SERVICE_NAME", service.Key));
XElement serviceSites = new XElement("SERVICE_SITES");
partyServices.Add(serviceSites);
foreach (var serviceSite in service.GroupBy(x => x.Field<string>("SITENAME")))
{
serviceSites.Add(new XElement("SITE_NAME", serviceSite.Key));
XElement siteNodes = new XElement("SITE_NODES");
serviceSites.Add(siteNodes);
string[] nodeNames = serviceSite.Select(x => x.Field<string>("NODENAME")).Distinct().ToArray();
foreach (string nodeName in nodeNames)
{
siteNodes.Add(new XElement("NODE_NAME", nodeName));
}
}
}
}
}
}
catch (Exception ex)
{
log.Error(ex.Message);
}
XmlSerializer myItemSerializer = new XmlSerializer(typeof(getCustomerSites));
using (var reader = doc.CreateReader())
{
sitedetailsResObj = (getCustomerSites)myItemSerializer.Deserialize(reader);
}
C# classes used to serialize
namespace ITSM_GIS_NRMIntegration.BusinessObjects
{
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class getCustomerSites:ResponseBase
{
private getCustomerSitesPARTY_SITE_NODES[] pARTY_SITE_NODESField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("PARTY_SITE_NODES")]
public getCustomerSitesPARTY_SITE_NODES[] PARTY_SITE_NODES
{
get
{
return this.pARTY_SITE_NODESField;
}
set
{
this.pARTY_SITE_NODESField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class getCustomerSitesPARTY_SITE_NODES
{
private uint cBCM_PARTY_IDField;
private string cBCM_PARTY_NAMEField;
private getCustomerSitesPARTY_SITE_NODESPARTY_SERVICES[] pARTY_SERVICESField;
/// <remarks/>
public uint CBCM_PARTY_ID
{
get
{
return this.cBCM_PARTY_IDField;
}
set
{
this.cBCM_PARTY_IDField = value;
}
}
/// <remarks/>
public string CBCM_PARTY_NAME
{
get
{
return this.cBCM_PARTY_NAMEField;
}
set
{
this.cBCM_PARTY_NAMEField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("PARTY_SERVICES")]
public getCustomerSitesPARTY_SITE_NODESPARTY_SERVICES[] PARTY_SERVICES
{
get
{
return this.pARTY_SERVICESField;
}
set
{
this.pARTY_SERVICESField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class getCustomerSitesPARTY_SITE_NODESPARTY_SERVICES
{
private string sERVICE_NAMEField;
private getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITES sERVICE_SITESField;
/// <remarks/>
public string SERVICE_NAME
{
get
{
return this.sERVICE_NAMEField;
}
set
{
this.sERVICE_NAMEField = value;
}
}
/// <remarks/>
public getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITES SERVICE_SITES
{
get
{
return this.sERVICE_SITESField;
}
set
{
this.sERVICE_SITESField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[KnownType(typeof(getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITESSITE_NODES))]
public partial class getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITES
{
private object[] sITE_NAMEField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("SITE_NAME", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("SITE_NODES", typeof(getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITESSITE_NODES))]
public object[] SITE_NAME
{
get
{
return this.sITE_NAMEField;
}
set
{
this.sITE_NAMEField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITESSITE_NODES
{
private string[] nODE_NAMEField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("NODE_NAME")]
public string[] NODE_NAME
{
get
{
return this.nODE_NAMEField;
}
set
{
this.nODE_NAMEField = value;
}
}
}
Error in SOAP UI is as shown below
An
Why aren't you using two properties instead of one?
public partial class getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITES
{
private object[] itemNamesField;
private object[] itemNodessField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("SITE_NAME", typeof(string))]
public object[] ItemNames
{
get
{
return this.itemNamesField;
}
set
{
this.itemNamesField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute("SITE_NODES", typeof(getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITESSITE_NODES))]
public object[] ItemNodes
{
get
{
return this.itemNodesField;
}
set
{
this.itemNodesField = value;
}
}
}
Below is the code to deserialize the xml. Linq is much faster to deserialize than the code below. So you have to decide if it is better to use your code or the code below. Usually I recommend if you have a schema (and the classes) and trying to get all the data it is better to use serialization. You are putting results into a datatable which I then recommend xml linq. I just want to so why I suggested to remove the base class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(getCustomerSites));
getCustomerSites sites = (getCustomerSites)serializer.Deserialize(reader);
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class getCustomerSites //: ResponseBase
{
private getCustomerSitesPARTY_SITE_NODES[] pARTY_SITE_NODESField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("PARTY_SITE_NODES")]
public getCustomerSitesPARTY_SITE_NODES[] PARTY_SITE_NODES
{
get
{
return this.pARTY_SITE_NODESField;
}
set
{
this.pARTY_SITE_NODESField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class getCustomerSitesPARTY_SITE_NODES
{
private uint cBCM_PARTY_IDField;
private string cBCM_PARTY_NAMEField;
private getCustomerSitesPARTY_SITE_NODESPARTY_SERVICES[] pARTY_SERVICESField;
/// <remarks/>
public uint CBCM_PARTY_ID
{
get
{
return this.cBCM_PARTY_IDField;
}
set
{
this.cBCM_PARTY_IDField = value;
}
}
/// <remarks/>
public string CBCM_PARTY_NAME
{
get
{
return this.cBCM_PARTY_NAMEField;
}
set
{
this.cBCM_PARTY_NAMEField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("PARTY_SERVICES")]
public getCustomerSitesPARTY_SITE_NODESPARTY_SERVICES[] PARTY_SERVICES
{
get
{
return this.pARTY_SERVICESField;
}
set
{
this.pARTY_SERVICESField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class getCustomerSitesPARTY_SITE_NODESPARTY_SERVICES
{
private string sERVICE_NAMEField;
private getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITES sERVICE_SITESField;
/// <remarks/>
public string SERVICE_NAME
{
get
{
return this.sERVICE_NAMEField;
}
set
{
this.sERVICE_NAMEField = value;
}
}
/// <remarks/>
public getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITES SERVICE_SITES
{
get
{
return this.sERVICE_SITESField;
}
set
{
this.sERVICE_SITESField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
//[KnownType(typeof(getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITESSITE_NODES))]
public partial class getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITES
{
private object[] itemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("SITE_NAME", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("SITE_NODES", typeof(getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITESSITE_NODES))]
public object[] Items
{
get
{
return this.itemsField;
}
set
{
this.itemsField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class getCustomerSitesPARTY_SITE_NODESPARTY_SERVICESSERVICE_SITESSITE_NODES
{
private string[] nODE_NAMEField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("NODE_NAME")]
public string[] NODE_NAME
{
get
{
return this.nODE_NAMEField;
}
set
{
this.nODE_NAMEField = value;
}
}
}
}
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'm adding a custom app settings section but I'm having trouble retrieving my newly added values. This is a .NET Core console project. Here is my config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="customAppSettings" type="MetricCollection.MetricCustomAppSettingSection, MetricCollection"/>
</configSections>
<appSettings>
<add key="metricTrackers" value=".\Trackers"/>
</appSettings>
<customAppSettings
productionServers="comma,seperated,list"
qaServers="other,comma,seperated,list">
<test
default="testvalue" />
</customAppSettings>
</configuration>
I'm able to get the productionServers and qaServers values but I am unable to get the test entry's value. I was planning on using this implementation for multiple projects so I have a base class that I inherit from. I've also tried putting it all in the child class to see if that was the issue and that didn't work either. Here's the child class:
public class MetricCustomAppSettingSection : BaseCustomAppSettingSection
{
[ConfigurationProperty("test", IsRequired = true)]
public CustomAppSettingElement Test
{
get { return (CustomAppSettingElement)base["test"]; }
}
}
public class MetricConfiguration : BaseConfiguration
{
private static MetricCustomAppSettingSection _customSection;
static MetricConfiguration()
{
_customSection = ConfigurationManager.GetSection("customAppSettings") as MetricCustomAppSettingSection;
}
// This doesn't work...
public static string Test
{
get { return GetAppSetting("Test", _customSection); }
}
}
And here is the base class:
public class CustomAppSettingElement : ConfigurationElement
{
#region Properties
/// <summary>
/// Default value which is required to be in each element
/// </summary>
[ConfigurationProperty("default", IsRequired = true)]
public string Default { get; set; }
/// <summary>
/// Development value which is optional for each element
/// </summary>
[ConfigurationProperty("development", IsRequired = false)]
public string Development { get; set; }
/// <summary>
/// QA value which is optional for each element
/// </summary>
[ConfigurationProperty("qa", IsRequired = false)]
public string QA { get; set; }
/// <summary>
/// Production value which is optional for each element
/// </summary>
[ConfigurationProperty("production", IsRequired = false)]
public string Production { get; set; }
#endregion
}
public class BaseCustomAppSettingSection : ConfigurationSection
{
/// <summary>
/// List of servers that are running the Production Zarga API
/// </summary>
[ConfigurationProperty("productionServers", IsRequired = true)]
public string ProductionServers
{
get { return (string)base["productionServers"]; }
}
/// <summary>
/// List of servers that are running the QA Zarga API
/// </summary>
[ConfigurationProperty("qaServers", IsRequired = true)]
public string QaServers
{
get { return (string)base["qaServers"]; }
}
}
public class BaseConfiguration
{
#region Fields
protected static bool _isQa = false;
protected static bool _isDevelopment = false;
protected static bool _isProduction = false;
#endregion Fields
static BaseConfiguration()
{
string host = IPGlobalProperties.GetIPGlobalProperties().HostName;
BaseCustomAppSettingSection baseCustomSection = ConfigurationManager.GetSection("customAppSettings") as BaseCustomAppSettingSection;
if (baseCustomSection.QaServers.IndexOf(host, StringComparison.OrdinalIgnoreCase) >= 0)
{
_isQa = true;
}
else if (baseCustomSection.ProductionServers.IndexOf(host, StringComparison.OrdinalIgnoreCase) >= 0)
{
_isProduction = true;
}
else
{
_isDevelopment = true;
}
}
protected static string GetCustomAppSetting(string defaultValue, string qaValue, string devValue, string prodValue)
{
if (_isQa)
{
return qaValue ?? defaultValue;
}
else if (_isDevelopment)
{
return devValue ?? defaultValue;
}
else
{
return prodValue ?? defaultValue;
}
}
/// <summary>
/// Gets the setting designated by the key.
/// </summary>
/// <param name="key">The key whose setting you want to get.</param>
/// <returns></returns>
protected static string GetAppSetting(string key, BaseCustomAppSettingSection customSection)
{
CustomAppSettingElement customSetting = (CustomAppSettingElement)customSection.GetType().GetProperty(key).GetValue(customSection);
return GetCustomAppSetting(customSetting.Default, customSetting.QA, customSetting.Development, customSetting.Production);
}
}
Thanks for the help.
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);
}
}
The problem is, as the title say I get an exception whenever I try to load a custom CustomConfiguration section from my .config file. The app.config file I try to load looks like this.
....
<configSections>
<sectionGroup name="MainSection">
...
<section name="Directories" type="MyNamespace.DirectoriesSettings, Assembly"/>
</sectionGroup>
</configSections>
....
<MainSection>
...
<Directories Count="1">
<Directory id="1" Path="Some\Path" Working="And\Another\Path" Country="US"/>
</Directories>
</MainSection>
....
And the code
namespace MyNamespace
{
internal class DirectoriesSettings : ConfigurationSection
{
[ConfigurationProperty("Count")]
public int Count { get { return Convert.ToInt32(base["Count"]); } }
[ConfigurationProperty("Directories", IsDefaultCollection = true, IsRequired = true)]
[ConfigurationCollection(typeof(DirectoryElement), AddItemName = "Directory", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public DirectoryElementCollection Directories { get { return (DirectoryElementCollection)base["Directories"]; } }
}
internal class DirectoryElementCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new DirectoryElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((DirectoryElement)element).Id;
}
}
internal class DirectoryElement : ConfigurationElement
{
[ConfigurationProperty("id", IsKey = true, IsRequired = true)]
public int Id
{
get { return Convert.ToInt32(this["id"]); }
set { this["id"] = value; }
}
[ConfigurationProperty("Path", IsKey = false, IsRequired = true)]
public string Path
{
get { return Convert.ToString(this["Path"]); }
set { this["Path"] = value; }
}
[ConfigurationProperty("Working", IsKey = false, IsRequired = true)]
public string Working
{
get { return Convert.ToString(this["Working"]); }
set { this["Working"] = value; }
}
[ConfigurationProperty("Country", IsKey = false, IsRequired = true)]
public string Country
{
get { return Convert.ToString(this["Country"]); }
set { this["Country"] = value; }
}
}
}
And the code to use it
class SettingsContainer
{
private const string PARENT_SECTION = "MainSection";
...
private DirectoriesSettings _directoriesSettings;
public DirectoriesSettings Directories { get { return _directoriesSettings; } }
...
public SettingsContainer()
{
...
_directoriesSettings = (DirectoriesSettings)ConfigurationManager.GetSection(string.Format("{0}/Directories", PARENT_SECTION));
...
}
}
The exception (Unrecognized element 'Directory') is thrown whenever I try to set the _directoriesSettings variable.
I think I am doing it right, but apparently I am missing something.
Any help will be greatly appreciated.
Solution:
I found where my problem was.
The property Directories inside DirectoriesSettings class should look like this
[ConfigurationCollection(typeof(DirectoryElement), AddItemName = "Directory", CollectionType = ConfigurationElementCollectionType.BasicMap)]
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
public DirectoryElementCollection Directories { get { return (DirectoryElementCollection)this[""]; } }
instead of
[ConfigurationCollection(typeof(DirectoryElement), AddItemName = "Directory", CollectionType = ConfigurationElementCollectionType.BasicMap)]
[ConfigurationProperty("Directories", IsDefaultCollection = true, IsRequired = true)]
public DirectoryElementCollection Directories { get { return (DirectoryElementCollection)base["Directories"]; } }