Unrecognized element exception with custom C# config
Asked Answered
F

1

9

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.

Fala answered 11/9, 2011 at 19:17 Comment(1)
See Also: How can I solve “Unrecognized element 'elementName'.Suds
F
11

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"; }
}
Fala answered 12/9, 2011 at 12:38 Comment(3)
Form me it was the "return ConfigurationElementCollectionType.BasicMap;" which I needed to change to "return ConfigurationElementCollectionType.AddRemoveClearMap;" but this post helped me get to that answer!Selfindulgent
This AddItemName solution is pretty obvious. Pretty intuitive. Pretty discoverable. Design the configuration framework so that the xml structure resembles your object model, until you try to add items to a collection, at which point you use the xml element <add /> instead of the object type/name. That'll keep 'em guessing. For about 6 hours.Fix
Overriding ElementName in the collection class was the crucial part to get this working for me. Setting AddItemName wasn't enough. Needless to say, this is missing from the MSDN examples.Ashur

© 2022 - 2024 — McMap. All rights reserved.