Custom Configuration, ConfigurationElements, and ConfigurationProperties
Asked Answered
W

5

14

I've been scouring the net for the last 3 days, and can't find any reference to this question. I've created a custom configuration class to be used with my app.config. Everything works fine. The problem comes in when a configuration property (of a configuration element) is not required, and is not defined in the app.config. It seems that default values are returned for the configuration property. Does anyone know how to determine if the property isn't defined in the app.config? (I've been trying to post my app.config, but can't figure out how to do it...anyone know how?)


//Main
namespace TestStub
{
    class Program
    {
        static void Main(string[] args)
        {
            CustomSettingsHandler config = (CustomSettingsHandler)ConfigurationManager.GetSection("CustomSettingsManager");
            Console.WriteLine("Setting1 {0}", config.Setting1.CustomSettingItem);
            Console.WriteLine("Setting2 {0}", config.Setting2.CustomSettingItem);
        }
    }
}

//Custom Configuration Class
namespace CustomConfiguration
{
    public class CustomSettingsHandler : ConfigurationSection
    {
        [ConfigurationProperty("setting1", IsRequired = false)]
        public CustomSettingElement Setting1 { get { return (CustomSettingElement)this["setting1"]; } }

        [ConfigurationProperty("setting2", IsRequired = false)]
        public CustomSettingElement Setting2 { get { return (CustomSettingElement)this["setting2"]; } }
    }

    public class CustomSettingElement : ConfigurationElement
    {
        [ConfigurationProperty("customsettingitem", IsRequired = false)]
        public int CustomSettingItem { get { return (int)this["customsettingitem"]; } }
    }
}
Wiedmann answered 20/2, 2009 at 3:4 Comment(0)
M
11

I found the best way is to override ConfigurationSection.PostDeserialize() and check the IsPresent property of each section member that derives from ConfigurationElement.

public class CustomSettingsHandler : ConfigurationSection
{
    // ...

    protected override void PostDeserialize()
    {
        foreach (ConfigurationProperty property in Properties)
        {
            var configElement = this[property] as ConfigurationElement;

            if (configElement != null 
                && !configElement.ElementInformation.IsPresent)
            {
                this[property] = null;
            }
        }

        base.PostDeserialize();
    }
}

Each ConfigurationElement that has not been read from the config file will be null afterwards.

Mclean answered 13/5, 2013 at 13:45 Comment(1)
As a side note, you don't have to do this at the PostDeserialize event. The ElementInformation is always available: Console.WriteLine("Setting1 {0}", config.Setting1.CustomSettingItem.ElementInformation.IsPresent ? "Y" : "N");Eight
P
4

The 2 things I can think of off the top of my head would be to use a DefaultValue, like so:

    [ConfigurationProperty("customsettingitem", DefaultValue = -1)]
    public int CustomSettingItem { get { return (int)this["customsettingitem"]; } }

Assuming there is some value that is invalid. In this case, CustomSettingItem == -1 means it wasnt set, and >= 0 was a value set in config. Of course that assumes -1 wasnt valid input in the first place.

Second idea is to use a nullable int instead:

    [ConfigurationProperty("customsettingitem", IsRequired = false)]
    public int? CustomSettingItem { get { return (int?)this["customsettingitem"]; } }

Now if nothing is set in config, it should default to null instead of 0.

Peeples answered 20/2, 2009 at 3:10 Comment(1)
That works, but I was hoping there was a way to suppress the default when the property is not defined. The work around I'm using right now is config.Setting2.IsPresentWiedmann
U
2

Try the following:

configElement.ElementInformation.Properties[propName].ValueOrigin = 
        PropertyValueOrigin.SetHere

The ValueOrigin property tells you where does the value come from.

Unmade answered 26/3, 2014 at 15:47 Comment(1)
IsPresent wasn't returning the expected value for some reason (it returned false for everything). ValueOrigin worked for me.Oxeyed
B
0

So far I've not been able to tell a property to be null if it isn't defined in the configuration file. It seems that in it's infinite wisdom, Microsoft decided you really mean String.Empty or new ConfigurationElement() when you type null.

The way I'm currently solving it is like this:

    bool _hasProp = true;
    protected override object OnRequiredPropertyNotFound(string name)
    {
        if (name == "prop")
        {
            _hasProp = false;
            return null; // note that this will still not make prop null
        }
        return base.OnRequiredPropertyNotFound(name);
    }

    [ConfigurationProperty("prop", IsRequired = true)]
    public string Prop
    {
        get { return _hasProp ? (string) this["prop"] : null; }
    }

It's a hack and will wrongly mark the property as required. If you're using a tool to edit your configuration file it won't like this.

Barney answered 6/1, 2011 at 14:35 Comment(0)
D
0

You can also check using the following:

config.Setting1.CustomSettingItem.ElementInformation.IsPresent 

it will give you false if it was not found in your config file.

Dilate answered 26/5, 2016 at 22:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.