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 (a
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.)
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.
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.
The resolving of the StringValidator can be done by any one of the following:
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; }
}