3

I have classes to read in a custom config file, which work in my (sandbox) MVC app, and in a console app. However, it fails to read anything except the top level section when it's run from the web forms app that actually needs it. They all target framework .Net 4.5. The custom config is a 'carrier' section that contains a list of carriers, each of which has their own settings. The web.config extracts:

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="CarrierSection" type="SmallWFApp.CarrierSection"/>
    </configSections>

The custom config section file:

<?xml version="1.0"?>
<CarrierSection>
  <carriers>
    <carrier name="ups" default-code="UPS0041" >
      <pickupreq value="N"/>
      <limits>
        <limit name="non-doc" weight="200" length="270" width="165" height="165" square="330" />
        <limit name="doc" weight="2.5"  length="0" width="0" height="0" square="0" />
        <limit name="consignment" max-eu="200" max-world="0"/>
      </limits>
      <services>
        <service name="document" caption="DOCUMENT EXPRESS" code="D" live="Y"/>
        <service name="parcel" caption="EXPRESS" code="N" live="Y" />
        <service name = "road" caption="ECONOMY ROAD" code="P" live="N" />
      </services>
    </carrier>
    <carrier name="dhl" default-code="DHL0014" >
      <pickupreq value="Y"/>
      <limits >
        <limit name="non-doc" weight="200" length="270" width="165" height="165" square="330"  />
        <limit name="doc"  weight="2.5"  length="0" width="0" height="0" square="0"/>
      </limits>
      <services>
        <service name="9am" caption="NEXT DAY 9AM"  code="9" />
        <service name = "noon" caption="NEXT DAY 12NOON"  code="2" />
      </services>
    </carrier>
  </carriers>
</CarrierSection>

The c# config section classes that (I think) provide the strong typing:

using System;
using System.Configuration;

namespace SmallWFApp
{
public class CarrierSection : ConfigurationSection
{
    [ConfigurationProperty("carriers")]
    public CarrierElementCollection Carriers
    {
        get { return this["carriers"] as CarrierElementCollection; }
    }
}

//-----------------------------------------

public class CarrierElementCollection : ConfigurationElementCollection
{
    protected override ConfigurationElement CreateNewElement()
    {
        return new CarrierElement();
    }
    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((CarrierElement)element).Name;
    }
    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.BasicMap; }
    }
    protected override string ElementName
    {
        get { return "carrier"; }
    }
    public CarrierElement this[int index]
    {
        get { return (CarrierElement)BaseGet(index); }
        set
        {
            if (BaseGet(index) != null)
            {
                BaseRemoveAt(index);
            }
            BaseAdd(index, value);
        }
    }
    new public CarrierElement this[string employeeID]
    {
        get { return (CarrierElement)BaseGet(employeeID); }
    }
    public bool ContainsKey(string key)
    {
        bool result = false;
        object[] keys = BaseGetAllKeys();
        foreach (object obj in keys)
        {
            if ((string)obj == key)
            {
                result = true;
                break;
            }
        }
        return result;
    }
}

//-----------------------------------------------------------------
public class CarrierElement : ConfigurationElement
{
    [ConfigurationProperty("name", DefaultValue = "Other", IsRequired = true, IsKey = true)]
     public string Name
    {
        get { return this["name"] as string; }
        set  { this["name"] = value;  }
    }


    [ConfigurationProperty("default-code", IsRequired = true)]
    public string DefaultCode
    {
        get  { return this["default-code"] as string;  }
        set  {  this["default-code"] = value;  }
    }

    [ConfigurationProperty("pickupreq")]
    public ReqPickupConfigElement ReqPickup
    {
        get  {  return base["pickupreq"] as ReqPickupConfigElement;  }
    }


    [ConfigurationProperty("limits")]
    public LimitElementCollection Limits
    {
        get  { return this["limits"] as LimitElementCollection; }
    }

    [ConfigurationProperty("services")]
    public ServiceElementCollection Services
    {
        get  { return this["services"] as ServiceElementCollection;  }
    }
}


//--------------------------------------------

public class ReqPickupConfigElement : System.Configuration.ConfigurationElement
{
    [ConfigurationProperty("value", DefaultValue = "N")]
    [StringValidator(MinLength = 1, MaxLength = 1)]

    public string Value
    {
        get   {  return base["value"] as string;  }
    }
}

The code in the code-behind-aspx.cs class that reads it:

try
{
    CarrierSection config =
                        (CarrierSection)System.Configuration.ConfigurationManager.GetSection(
                        "CarrierSection");

    if (config != null)
    {
        foreach (CarrierElement app in config.Carriers)
        {
            //... (never comes in here) ...
        }

        //lbConfigread.Text = found.ToString();
    }
}
catch (Exception ex)
{
    //...
}

The c# configuration collection/elements to read the 'limits' for each carrier:

namespace SmallWFApp
{
    public class LimitElementCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new LimitElement();
        }
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((LimitElement)element).Name;
        }
        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }
        protected override string ElementName
        {
            get { return "limit"; }
        }
        public LimitElement this[int index]
        {
            get { return (LimitElement)BaseGet(index); }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                }
                BaseAdd(index, value);
            }
        }
        new public LimitElement this[string employeeID]
        {
            get { return (LimitElement)BaseGet(employeeID); }
        }
        public bool ContainsKey(string key)
        {
            bool result = false;
            object[] keys = BaseGetAllKeys();
            foreach (object obj in keys)
            {
                if ((string)obj == key)
                {
                    result = true;
                    break;
                }
            }
            return result;
        }
    }
    public class LimitElement : ConfigurationElement
    {
        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return this["name"] as string; }
            set  {  this["name"] = value;  }
        }

        [ConfigurationProperty("weight", IsRequired = false)]
        public string Weight
        {
            get  {  return this["weight"] as string;  }
            set {  this["weight"] = value; }
        }

        [ConfigurationProperty("length", IsRequired = false)]
        public string Length
        {
            get  {  return this["length"] as string; }
            set  { this["length"] = value;  }
        }
        [ConfigurationProperty("width", IsRequired = false)]
        public string Width
        {
            get  { return this["width"] as string; }
            set  { this["width"] = value;  }
        }
        [ConfigurationProperty("height", IsRequired = false)]
        public string Height
        {
            get  { return this["height"] as string; }
            set { this["height"] = value;  }
        }
        [ConfigurationProperty("square", IsRequired = false)]
        public string Square
        {
            get {  return this["square"] as string;  }
            set  { this["square"] = value; }
        }

        // for total consignment

        [ConfigurationProperty("max-eu", IsRequired = false)]
        public string MaxEU
        {
            get  {  return this["max-eu"] as string;  }
            set  {  this["max-eu"] = value;  }
        }
        [ConfigurationProperty("max-world", IsRequired = false)]
        public string MaxWorld
        {
            get  { return this["max-world"] as string; }
            set  { this["max-world"] = value;  }
        }
    }
}

The c# configuration collection/elements to read the 'service' for each carrier:

namespace SmallWFApp
{
    public class ServiceElementCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new ServiceElement();
        }
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ServiceElement)element).Name;
        }
        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }
        protected override string ElementName
        {
            get { return "service"; }
        }
        public ServiceElement this[int index]
        {
            get { return (ServiceElement)BaseGet(index); }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                }
                BaseAdd(index, value);
            }
        }
        new public ServiceElement this[string employeeID]
        {
            get { return (ServiceElement)BaseGet(employeeID); }
        }
        public bool ContainsKey(string key)
        {
            bool result = false;
            object[] keys = BaseGetAllKeys();
            foreach (object obj in keys)
            {
                if ((string)obj == key)
                {
                    result = true;
                    break;
                }
            }
            return result;
        }
    }
    public class ServiceElement : ConfigurationElement
    {
        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get {  return this["name"] as string; }
            set  { this["name"] = value;  }
        }

        [ConfigurationProperty("caption", IsRequired = true)]
        public string Caption
        {
            get  { return this["caption"] as string; }
            set  { this["caption"] = value;  }
        }

        [ConfigurationProperty("code", IsRequired = true)]
        public string Code
        {
            get  { return this["code"] as string;  }
            set { this["code"] = value;  }
        }

        [ConfigurationProperty("live", IsRequired = false)]
        public string Live
        {
            get  {  return this["live"] as string;  }
            set  {  this["live"] = value; }
        }
    }
}

So when you run it, there is no error, but when you examine the variable in the debugger, the collection of carrier property is null:

?config.Carriers
Count = 0
    AddElementName: "add"
    ClearElementName: "clear"
    CollectionType: BasicMap
    Count: 0
    CurrentConfiguration: null
    ElementInformation: {System.Configuration.ElementInformation}
    ElementName: "carrier"
    ElementProperty: {System.Configuration.ConfigurationElementProperty}
    ...
    Properties: {System.Configuration.ConfigurationPropertyCollection}
    ...

If this contains some obvious faux-pas then I'm sorry, but it's driving me to distraction; I need to have released this fix some days ago!

8
  • Where are defined limits, limit and services, service? If I remove these nodes in the config I get 2 Carriers. Commented Jan 23, 2017 at 15:32
  • Thanks for looking! I'd removed them in an attempt to be more readable, However, if I replace them, it still has no carrier collection being returned, So, I've restored them in my question, and would be grateful if you could take another look? Commented Jan 23, 2017 at 15:53
  • I'm sorry, I couldn't reproduce your problem. I got 2 Carriers even with the limits and services nodes. Is your CarrierSection in the Web.config or in a separate configuration file? Commented Jan 23, 2017 at 16:07
  • Yes, the CarrierSection is in another file, parcelcarriers.config. It's properties include Build Action: Content and Copy to the output directory: always. Commented Jan 23, 2017 at 16:11
  • I had forgotten to put <CarrierSection configSource="parcelcarriers.config" /> in the web.config file, after recompiling it worked! Commented Jan 23, 2017 at 16:16

1 Answer 1

2

You have to specify in your Web.config file where is located your custom configuration file parcelcarriers.config:

<CarrierSection configSource="parcelcarriers.config"/>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.