为啥自定义配置部分的 StringValidator 总是失败?

Posted

技术标签:

【中文标题】为啥自定义配置部分的 StringValidator 总是失败?【英文标题】:Why does StringValidator always fail for custom configuration section?为什么自定义配置部分的 StringValidator 总是失败? 【发布时间】:2011-04-04 20:46:24 【问题描述】:

我通过继承 ConfigurationSection 在 c# 类库中创建了一个自定义配置部分。我在我的 Web 应用程序(也是 c#、ASP.NET)中引用了类库,填写了适当的属性,一切都很好。当我开始添加验证器时,问题就开始了。

例如这个属性:

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

它工作正常,但只要我添加这个:

    [StringValidator(MinLength=1)]  

它会发生以下错误:

属性“appCode”的值无效。错误是:字符串必须至少有 1 个字符长。

即使我的web.config 文件中有一个有效的appCode 值,我也会收到此错误。如果我删除验证器,它会完美运行。有谁知道如何解决这个问题?

【问题讨论】:

我已经阅读了整个系列,不幸的是它没有解释我收到错误的原因。 您是否尝试过使用(有效)默认值初始化 ApplicationCode 属性?似乎验证规则在从配置文件中读取值之前的某个时间点失败。 是的,默认情况下也能正常工作。并非所有字段都具有有效/合理的默认值,尤其是可选字段,因此它似乎无法从配置初始化,这很烦人。 【参考方案1】:

似乎答案确实是因为它们没有默认值。看起来很奇怪,所以如果有人有更好的答案,请告诉我,我会接受他们的。

【讨论】:

【参考方案2】:

根据以下实现,我能够通过使用显式 ConfigurationProperty 作为属性集合的键而不是字符串来解决此问题:

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; 
    

(此代码与 AssemblyInfo 配置元素类所反映的代码紧密建模。我仍然希望不必重复验证,但至少此代码允许我指定空白默认值,同时仍然需要输入一个值。)

【讨论】:

你说得对,我希望我也不必这样做。不过我试过了,它可以工作,所以谢谢。 我花了一整天的时间来解决这个问题。太棒了——这对我有用。【参考方案3】:

我有一段时间遇到这个问题,然后我意识到验证器不是为了使属性或元素成为必需的,它们是为了验证它们。

要使属性成为必需,您需要使用 IsRequired 和 ConfigrationPropertyOptions.IsRequired,例如

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

或者(如果使用 api)

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

这样做,配置框架将自己处理需要的属性,验证器处理验证值中的内容。验证器并不意味着需要做一些事情。

这也适用于需要子元素的元素。例如。如果您正在使用子元素制作自定义 ConfigSection 并且需要一个子元素。但是,如果您创建一个继承自 ConfigurationValidatorBase 的 CustomValidator,则需要使用 ElementInformation.IsPresent,例如

            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.");
        

长话短说,您缺少属性的选项部分以使其成为必需,并且不应使用 StringValidator(MinLength=1) 使其成为必需。事实上 StringValidator(MinLength=1) 是完全多余的。如果您将其设为必需,则 MinLength=1 不可能在没有必需首先失败的情况下失败,因为如果它存在,则保证至少有 1 个字符长。

将您的验证器更改为

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

然后放弃字符串验证器。

【讨论】:

【参考方案4】:

StringValidator 的解析可以通过以下任一方式完成:

删除 MinLength 参数 设置 MinLength = 0 删除 StringValidator 属性 将 DefaultValue 添加到 ConfigurationProperty 属性

该属性的理想定义如下:

[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; 

【讨论】:

以上是关于为啥自定义配置部分的 StringValidator 总是失败?的主要内容,如果未能解决你的问题,请参考以下文章

Android - 为啥我的图像视图占据了大部分屏幕?我希望它占据自定义应用栏下方的所有空间

为啥我的自定义 XML RPC 获取配置不起作用?

为啥自定义光标图像显示不正确?

为啥我的自定义控件不总是接收 MouseEnter 事件?

webpack中loader为啥是从后往前加载的

为啥不推荐使用 JScript 在 WiX 中实现自定义操作?