3

Having a horrible time reading a custom configuration section from web.config: I am using Configuration Section Designer (http://csd.codeplex.com/).

UPDATE:

here is the error I am getting:

System.Configuration.ConfigurationErrorsException: An error occurred creating the configuration section handler for SendToTestConfig/sendToTestIndexConfig: No parameterless constructor defined for this object. (C:\TFS\Mainline\Business.Utility.SendToTest\Business.Utility.SendToTest\web.config line 20) ---> System.MissingMethodException: No parameterless constructor defined for this object. at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache) at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache)

Here is my auto-generated configuration section:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.225
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Business.Utility.SendToTest.Configuration
{


    /// <summary>
    /// The SendToTestIndexConfig Configuration Section.
    /// </summary>
    public partial class SendToTestIndexConfig : global::System.Configuration.ConfigurationSection
    {


        #region Singleton Instance
        /// <summary>
        /// The XML name of the SendToTestIndexConfig Configuration Section.
        /// </summary>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.0.0")]
        internal const string SendToTestIndexConfigSectionName = "sendToTestIndexConfig";

        /// <summary>
        /// Gets the SendToTestIndexConfig instance.
        /// </summary>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.0.0")]
        public static global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig Instance
        {
            get
            {
                return ((global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig)(global::System.Configuration.ConfigurationManager.GetSection(global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig.SendToTestIndexConfigSectionName)));
            }
        }
        #endregion

        #region Xmlns Property
        /// <summary>
        /// The XML name of the <see cref="Xmlns"/> property.
        /// </summary>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.0.0")]
        internal const string XmlnsPropertyName = "xmlns";

        /// <summary>
        /// Gets the XML namespace of this Configuration Section.
        /// </summary>
        /// <remarks>
        /// This property makes sure that if the configuration file contains the XML namespace,
        /// the parser doesn't throw an exception because it encounters the unknown "xmlns" attribute.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.0.0")]
        [global::System.Configuration.ConfigurationPropertyAttribute(global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig.XmlnsPropertyName, IsRequired=false, IsKey=false, IsDefaultCollection=false)]
        public string Xmlns
        {
            get
            {
                return ((string)(base[global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig.XmlnsPropertyName]));
            }
        }
        #endregion

        #region IsReadOnly override
        /// <summary>
        /// Gets a value indicating whether the element is read-only.
        /// </summary>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.0.0")]
        public override bool IsReadOnly()
        {
            return false;
        }
        #endregion

        #region appGroups Property
        /// <summary>
        /// The XML name of the <see cref="appGroups"/> property.
        /// </summary>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.0.0")]
        internal const string appGroupsPropertyName = "appGroups";

        /// <summary>
        /// Gets or sets the appGroups.
        /// </summary>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.0.0")]
        [global::System.ComponentModel.DescriptionAttribute("The appGroups.")]
        [global::System.Configuration.ConfigurationPropertyAttribute(global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig.appGroupsPropertyName, IsRequired=true, IsKey=false, IsDefaultCollection=false)]
        public global::Business.Utility.SendToTest.Configuration.AppGroupSettingsCollection appGroups
        {
            get
            {
                return ((global::Business.Utility.SendToTest.Configuration.AppGroupSettingsCollection)(base[global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig.appGroupsPropertyName]));
            }
            set
            {
                base[global::Business.Utility.SendToTest.Configuration.SendToTestIndexConfig.appGroupsPropertyName] = value;
            }
        }
        #endregion
    }
}
namespace Business.Utility.SendToTest.Configuration
{
   ... 

And here is my config file:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="SendToTestConfig" type="System.Configuration.ConfigurationSectionGroup, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
      <section name="sendToTestIndexConfig" type="Business.Utility.SendToTest.Configuration.SendToTestIndexConfig, Business.Utility.SendToTest.Configuration"/>
    </sectionGroup>
etc.

  </configSections>
    <SendToTestConfig xmlns="Business.Utility.SendToTest.Configuration">
      <sendToTestIndexConfig>
        <appGroups>
          <!-- TODO Change indexFileNamePrefix to desired value-->
          <appGroupSettings name="ItemBased" indexFileNamePrefix="S" indexFolderLocation="C:\TFS\Mainline\Business.Utility.SendToTest\Business.Utility.SendToTest" imageFolderLocation="C:\TFS\Mainline\Business.Utility.SendToTest\Business.Utility.SendToTest">
            <topicEntries>
              <topicEntry topicIDSuffix="DATE" addDuplicateVSAMEntry="true">
                <itemSubFields>
                  <subField index="0" typeName="Date"/>
                </itemSubFields>
              </topicEntry>
              <topicEntry topicIDSuffix="Item" addDuplicateVSAMEntry="true">
                <itemSubFields>
                  <subField index="0" typeName="ItemNumber"/>
                </itemSubFields>
              </topicEntry>
              <topicEntry topicIDSuffix="DESCR">
                <itemSubFields>
                  <subField index="0" typeName="LongDescription"/>
                </itemSubFields>
              </topicEntry>
            </topicEntries>
          </appGroupSettings>
      </appGroups>
    </sendToTestIndexConfig>
  </SendToTestConfig>
...
</configuration>

I have tried all of the following, but I keep getting null for the first few config (which I think makes sense), and getting the abovementioned exception for the rest.

//These return null:
SendToTestIndexConfig config = SendToTestIndexConfig.Instance;
//SendToTestIndexConfig config = (SendToTestIndexConfig) ConfigurationManager.GetSection("sendToTestIndexConfig");
//SendToTestIndexConfig configb = (SendToTestIndexConfig)WebConfigurationManager.GetSection("sendToTestIndexConfig");
//SendToTestIndexConfig configc = (SendToTestIndexConfig)WebConfigurationManager.OpenWebConfiguration(null).GetSection("sendToTestIndexConfig");
//SendToTestIndexConfig configd = (SendToTestIndexConfig)WebConfigurationManager.GetWebApplicationSection("sendToTestIndexConfig");
//SendToTestIndexConfig configf = (SendToTestIndexConfig)WebConfigurationManager.GetSection("sendToTestIndexConfig");


////These throw a "parameterless constructor error" on object "SendToTestConfig/sendToTestIndexConfig"
//SendToTestIndexConfig configg = (SendToTestIndexConfig)WebConfigurationManager.GetSection("SendToTestConfig/sendToTestIndexConfig");
//SendToTestIndexConfig configh = (SendToTestIndexConfig)WebConfigurationManager.OpenWebConfiguration(null).GetSection("SendToTestConfig/sendToTestIndexConfig");
//SendToTestIndexConfig configi = (SendToTestIndexConfig)WebConfigurationManager.GetWebApplicationSection("SendToTestConfig/sendToTestIndexConfig");
//SendToTestIndexConfig configj = (SendToTestIndexConfig)WebConfigurationManager.GetSection("SendToTestConfig/sendToTestIndexConfig");

I'm guessing it has something to do with my naming. ConfigurationManager.AppSettings works fine, so I know I have the right web.config.

xdhmoore
  • 8,935
  • 11
  • 47
  • 90

2 Answers2

4

Actually, the solution to the problem is succinctly stated in an example for the GenericEnumConverter on MSDN. I did the same thing you probably did and explicitly set the [TypeConverter(typeof(GenericEnumConverter))] attrbibute on one of my configuration section properties and got the same error. According to the documentation for GenericEnumConverter linked to above, you do not need to set this attribute in order to use the GenericEnumConverter type converter--it is called implicitly by the framework. Remove that attribute from your configuration property specifications, and this error should disappear and everything should just work.

Here is an example of a configuration section property that uses an Enum:

    public enum UsernameFormat
    {
        DownLevelDomainName,
        UsernameOnly,
        UserPrincipalName
    }

    public class WindowsADElement : ConfigurationElement
    {
        // This property will implicitly use the GenericEnumConverter type converter.
        [ConfigurationProperty("usernameFormat", IsRequired=true, DefaultValue=UsernameFormat.UserPrincipalName)]
        public UsernameFormat UsernameFormat
        {
            get { return (UsernameFormat)this["usernameFormat"]; }
            set { this["usernameFormat"] = value; }
    }

Then, to use it in code:

    MyConfigurationSection config = ConfigurationManager.GetSection("myConfigurationSection") as MyConfigurationSection;
    UsernameFormat format = config.UsernameLookup.WindowsAD.UsernameFormat;

Hope that helps.

fourpastmidnight
  • 4,032
  • 1
  • 35
  • 48
2

I am not sure if this is the best solution, but I was able to get around the problem. The error was because I was using the GenericEnumTypeConverter class to convert the config strings to the AppGroup and SubFieldTypes enums. I created my own custom TypeConverters, and it solved the problem. Apparently, GenericEnumTypeConverter has no parameterless constructors, requiring the enum type for the constructor. Would love to know if there is a way to use GenericEnumTypeConverter, but this worked for me.

This clued me in on the answer: Configuration Error With Custom Behaviour

Community
  • 1
  • 1
xdhmoore
  • 8,935
  • 11
  • 47
  • 90