开发者

Why does StringValidator always fail for custom configuration section?

开发者 https://www.devze.com 2023-01-13 16:23 出处:网络
I have created a custom configuration section in a c# class library by inheriting from ConfigurationSection.I reference the class library in my web application (also c#, ASP.NET), fill in the appropri

I have created a custom configuration section in a c# class library by inheriting from ConfigurationSection. I reference the class library in my web application (also c#, ASP.NET), fill in the appropriate attributes and everything works great. The problem starts when I start adding validators.

For example, this property:

    [ConfigurationProperty("appCode", IsRequired = true)]
    public string ApplicationCode
    {
        get
        {
            return (string)base["appCode"];
        }
        set
        {
            base["appCode"] = value;
        }
    }

As is it works fine, but as soon as I add this:

    [StringValidator(MinLength=1)]  

It bombs with the following error:

The value for the property 'appCode' is not valid. The error is: The string must be at least 1 characters long.

I get this error even though a valid appCode value is in my web.config file. If I remove the validator it works perfectly. Does anyone know how to get aro开发者_C百科und this?


I was able to work around this issue by using an explicit ConfigurationProperty as the key to my properties collection rather than a string, as per the following implementation:

public class AssemblyElement : ConfigurationElement
{
    private static readonly ConfigurationProperty _propAssembly;
    private static readonly ConfigurationPropertyCollection _properties;

    static AssemblyElement()
    {
        _propAssembly = new ConfigurationProperty("assembly", typeof(string), null, null, new StringValidator(1), ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);
        _properties = new ConfigurationPropertyCollection();
        _properties.Add(_propAssembly);
    }

    internal AssemblyElement() { }
    public AssemblyElement(string assemblyName)
    {
        this.Assembly = assemblyName;
    }

    [ConfigurationProperty("assembly", IsRequired = true, IsKey = true, DefaultValue = "")]
    [StringValidator(MinLength = 1)]
    public string Assembly
    {
        get { return (string)base[_propAssembly]; }
        set { base[_propAssembly] = value; }
    }

    internal AssemblyName AssemblyName
    {
        get { return new AssemblyName(this.Assembly); }
    }

    protected override ConfigurationPropertyCollection Properties
    {
        get { return _properties; }
    }
}

(This code is closely modeled after the code reflected from the AssemblyInfo configuration element class. I still wish I didn't have to duplicate my validations, but at least this code allows me to specify a blank default value while still requiring a value to be entered.)


Seems like the answer is indeed because they don't have a default value. Seems odd, so if someone has a better answer let me know and I'll accept theirs.


I had this problem for a while, then I realized that the validators are not for making attribute or elements required, they are for validating them.

To make a property required you need to use the IsRequired and ConfigrationPropertyOptions.IsRequired, e.g.

[ConfigurationProperty("casLogoutUrl", DefaultValue = null, IsRequired = true, Options = ConfigurationPropertyOptions.IsRequired)]
[StringValidator(MinLength=10)]

Or (if using the api)

ConfigurationProperty casLoginUrl = new ConfigurationProperty("casLoginUrl", typeof(string), null, null, new StringValidator(1), ConfigurationPropertyOptions.IsRequired);

Doing this, the Configuration framework will handle the property being required itself, and the validator handles validating what's in the value. Validators are not meant for making something required.

This also works on elements to make child elements required. E.g. if you are making a custom ConfigSection with child elements and need a child element to be required. However, if you make a CustomValidator that inherits from ConfigurationValidatorBase, you need to make use of ElementInformation.IsPresent, e.g.

            public override void Validate(object value)
        {
            CredentialConfigurationElement element = (CredentialConfigurationElement)value;
            if (!element.ElementInformation.IsPresent)
                return; //IsRequired is handle by the framework, don't throw error here  only throw an error if the element is present and it fails validation.
            if (string.IsNullOrEmpty(element.UserName) || string.IsNullOrEmpty(element.Password))
                throw new ConfigurationErrorsException("The restCredentials element is missing one or more required Attribute: userName or password.");
        }

Long story short, you are missing the options part of your attribute to make it required and shouldn't use StringValidator(MinLength=1) to make it required. In fact StringValidator(MinLength=1) is completely redundant. If you make it required it's impossible for MinLength=1 to fail without the Required failing first because if it's present, it's guaranteed to be at least 1 character long.

Change your validator to

[ConfigurationProperty("appCode", IsRequired = true, Options=ConfigurationPropertyOptions.IsRequired)]

Then ditch the string validator.


The resolving of the StringValidator can be done by any one of the following:

  • Removing MinLength argument
  • Setting MinLength = 0
  • Removing the StringValidator Attribute
  • Adding DefaultValue to the ConfigurationProperty Attribute

The Ideal definition for the property is like:

[ConfigurationProperty("title", IsRequired = true, DefaultValue = "something")]
[StringValidator(InvalidCharacters = "~!@#$%^&*()[]{}/;’\"|\\"
  , MinLength = 1
  , MaxLength = 256)]
public string Title
{
    get { return this["title"] as string; }
    set { this["title"] = value; }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消