9

I'm having this wierd problem... in my code whether I set the value of IsRequired to false or true then it stays false.. However if I put in a DefaultValue it works?

The non-working code is:

public class FtpSettingsSection : ConfigurationSection
{
    [ConfigurationProperty("host", IsRequired = true)]
    public HostElement Host
    {
        get { return (HostElement)this["host"]; }
        set { this["host"] = value; }
    }

}

public class HostElement : ConfigurationElement
{
    [ConfigurationProperty("URL", IsRequired = true)]
    public string URL
    {
        get { return (string)this["URL"]; }
        set { this["URL"] = value; }
    }
}

and the working code is:

public class FtpSettingsSection : ConfigurationSection
{
    [ConfigurationProperty("host", DefaultValue = "", IsRequired = true)]
    public HostElement Host
    {
        get { return (HostElement)this["host"]; }
        set { this["host"] = value; }
    }

}

public class HostElement : ConfigurationElement
{
    [ConfigurationProperty("URL", DefaultValue = "", IsRequired = true)]
    public string URL
    {
        get { return (string)this["URL"]; }
        set { this["URL"] = value; }
    }
}

How come that I need to set DefaultValue to ""?

ebb
  • 9,297
  • 18
  • 72
  • 123

4 Answers4

6

I have encountered the same problem and found the solution here http://msdn.microsoft.com/en-us/library/system.configuration.configurationpropertyattribute%28v=vs.90%29.aspx#1. The comment on ConfigurationPropertyAttribute isn't completely correct, but it explains the basics of the problem:

The IsRequired member of ConfigurationPropertyAttribute does not work when applied to a child object (deriving from ConfigurationElement). When the subsystem reflects over the attributes of the parent section/element to determine which configuration properties are defined it will create a new instance (of the appropriate type) for each child element and store it in the parent's value list. Later, when it validates whether all required properties have been specified or not, it cannot differentiate between a default initialized child element and one that was explicitly contained in the configuration file.

The most ideal workaround would be to programmatically declare the required elements through the ConfigurationProperty class. This requires substantial more work than the declarative approach. An alternative...

As far as I can tell the alternative is incorrect.

An example of the programmatic model can be found on the ConfigurationProperty page. I have managed to fix the problem for myself by declaring the properties I need required in the constructor of my custom element and leaving everything else the same.

I suspect for you it is not actually working when you add DefaultValue, but rather throwing an exception for a different reason. You will have to drill down to the end of the InnerException chain to find the ConfigurationErrorsException. The correct message when a required property is missing is "Required attribute 'host' not found. (C:\path\to\yourproject\bin\Debug\yourproject.vshost.exe.Config line ##)"

When you provide an empty string default value the configuration subsystem will try to parse that string into a HostElement and fail. The resulting ConfigurationErrorsException has the message "The default value of the property 'host' cannot be parsed. The error is: Object reference not set to an instance of an object. (C:\path\to\yourproject\bin\Debug\yourproject.vshost.exe.Config line ##)"

Community
  • 1
  • 1
Yogh
  • 591
  • 6
  • 17
4

Digging up a dead thread. But I accidentally found a work around for this.

In your custom section constructor, make a reference to a custom element's ElementInformation. By doing that, another instance of your custom section will created in the element's context. And for some reason that I don't understand fully, the IsRequired property is honored.

public class FtpSettingsSection : ConfigurationSection
{
    public FtpSettingsSection() 
    {
        // force it to double load.
        if (this.Host.ElementInformation.IsPresent) ;
    }

    [ConfigurationProperty("host", IsRequired = true)]
    public HostElement Host
    {
        get { return (HostElement)this["host"]; }
        set { this["host"] = value; }
    }
}
Isen Ng
  • 1,307
  • 1
  • 11
  • 23
3

Sorry for necroposting, but this problem hit me too but in a more peculiar way and my solution also applies to the question asked.

I implemented reloading a config without restarting a process. When the process starts, the IsRequired attribute is "ignored" and the ConfigurationElement is silently initialized with default values. But when the config is reloaded, the IsRequired attributed is respected! So I hardcoded reloading configuration on process start and it solved the problem of missing exception!

Pseudocode:

config = (SampleConfiguration)ConfigurationManager.GetSection(ConfigSectionName);
// <-- no exception thrown for missing required properties

ConfigurationManager.RefreshSection(ConfigSectionName);

config = (SampleConfiguration)ConfigurationManager.GetSection(ConfigSectionName);
// <-- exception thrown!
Max Yakimets
  • 1,195
  • 7
  • 12
0

I am assuming you dont have the URL propertie's value serialized in your configuration. So when the configuration is being loaded the ConfigurationManager checks the attributes to see if the property value required and then throws exception if finds no value. If default value is set, then that value is used if none found in the config.

dexter
  • 7,063
  • 9
  • 54
  • 71
  • 1
    The first example of code dosent throw any exception even if the host property isnt defined in the config file? – ebb Nov 04 '10 at 12:58
  • The first example will throw an exception, the second with the default attribute won't. – dexter Nov 04 '10 at 20:58
  • Actually I tested this and the FIRST example does not throw an exception. In a test console app IsRequired appears to be getting ignored. If it IsRequired you shouldn't put default value because then it actually is not required. If you flag it IsRequired=true then it should throw an exception if you don't provide a default but it does not. I tested in .Net 4. – Rodney S. Foley Nov 11 '10 at 02:03