扩展 ASP.NET 验证器

Posted

技术标签:

【中文标题】扩展 ASP.NET 验证器【英文标题】:Extending ASP.NET validators 【发布时间】:2010-08-01 06:53:04 【问题描述】:

我想扩展 asp.net 验证器,以便我可以使一个验证器依赖于另一个验证器。我的情况是我们必须验证文本框中的日期。通常我会使用RequiredFieldValidator(确保提供日期)、CompareValidator(确保日期是日期)和 RangeValidator(确保日期在要求的限制内)的组合。

这样做的问题是验证器不相互依赖,因此用户可能会同时看到每个验证器的所有三个消息,而我们真正希望他们看到的是最相关的消息,即如果他们在日期文本框中输入“abc”,则不适合向他们显示日期不在有效范围内的消息(尽管从技术上讲,我认为这是真的)。​​

目前,为了提供这种功能,我们使用 CustomValidator 并将所有三个验证放在服务器验证事件处理程序中,并根据验证失败以编程方式更改错误消息。

我想把它标准化一点,因为它在这个应用程序中发生了很多,我想如果我可以让验证器相互依赖,这将解决问题并允许我们利用客户端验证,而不必进行回发,尤其是处理自定义验证。

这个想法是,如果一个验证器依赖于另一个验证器,如果该“主”有效,那么被依赖的验证器将执行其正常验证(EvaluateIsValid()),否则如果主验证器无效,则其他依赖验证器将有效.

我通过继承框架中已经提供的各种验证器控件提出了以下解决方案。

public class RequiredFieldDependentValidator : RequiredFieldValidator

    [Description("The validation control to depend on for determining if validation should occur")]
    public string ValidationControlToDependOn
    
        get
        
            object obj = ViewState["ValidationControlToDependOn"];
            if (obj != null) return (string) obj;
            return null;
        
        set
        
            Control control = FindControl(value);
            if (control is IValidator)
                ViewState["ValidationControlToDependOn"] = value;
            else
                throw new HttpException("ValidationControlToDependOn is not a validation control");
        
    

    protected override bool EvaluateIsValid()
    
        IValidator validationControlToDependOn = FindControl(ValidationControlToDependOn) as IValidator;

        if(validationControlToDependOn != null)
        
            return !validationControlToDependOn.IsValid || base.EvaluateIsValid();
        

        return base.EvaluateIsValid();
    

目前我刚刚为RequiredFieldValidator编写了代码,理想情况下我想为所有验证器提供此功能,但如果不将上述代码复制到每个单独类型的验证器的类似类中,我看不到这样做的方法我想提供此功能,因此如果有任何问题,我将不得不返回并单独更改每个验证器类型的此代码。

有没有一种方法可以让我“集中”这段代码并在验证器中轻松使用它,而不必从头开始编写整个验证器,这样我就可以更改它们从更远的地方继承的类。

干杯,

【问题讨论】:

【参考方案1】:

您可以覆盖页面库中的 Validate 方法。要在页面中添加验证依赖信息,您可以实现一个未呈现的控件:

<my:ValidationDependency TargetControl="RegExp1" Dependency="Required1" />

【讨论】:

【参考方案2】:

您可能想要查看 WebControlAdapter。

基本上允许您覆盖 web 控件的某些方法(如果需要,有条件地适用于某些浏览器,但这里可以适用于所有浏览器)。

在您的情况下,您可能希望重写 EvaluateIsValid 方法并检查控件是否对“父”验证器有任何依赖。

例如,我们最近创建了一个 TextBox 适配器,用于向控件呈现“maxlength”属性。

Public Class TextBoxAdapter
        Inherits WebControlAdapter

        Private ReadOnly Property TextBoxControl() As TextBox
            Get
                Return DirectCast(MyBase.Control, TextBox)
            End Get
        End Property

        Protected Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.htmlTextWriter)
            If TextBoxControl.TextMode = TextBoxMode.MultiLine AndAlso TextBoxControl.MaxLength > 0 Then
                writer.AddAttribute("maxlength", TextBoxControl.MaxLength.ToString)
            End If

            MyBase.RenderBeginTag(writer)
        End Sub
    End Class

要使用它,只需在您的 App_Browsers 目录中创建一个 .browser 文件并在那里设置适配器:

<browsers>
    <browser refID="Default">
        <controlAdapters>
            <adapter controlType="System.Web.UI.WebControls.TextBox"
               adapterType="TextBoxAdapter" />
        </controlAdapters>
    </browser>
</browsers>

在您的案例中仍然存在的唯一复杂情况是如何存储依赖验证器,以便 EvaluateIsValid 能够访问此目录。您可能会考虑像 Onof 建议的非渲染控件或 Viewstate/Cookie/其他存储机制。

【讨论】:

【参考方案3】:

您可以拥有 List 类型的 ValidationControlToDependOn 属性并将验证器添加到列表中。所以我们可以假设后面添加的验证器依赖于之前添加的验证器。

所以你的protected override bool EvaluateIsValid()

会有所改变

foreach(IValidator validator in ValidationControlToDependOn)

return !validator.IsValid;


【讨论】:

这不会使页面上的每个验证器都依赖于前一个验证器吗?而且我认为我仍然需要对每个验证器进行子类化【参考方案4】:

我正在研究控制扩展器,这似乎很有希望,但除了 AJAX 之外,我找不到很多例子。

【讨论】:

我试过了,但是你不能覆盖扩展控件的方法。 IMO 避免子类化的唯一方法是覆盖 Page.Validate()。

以上是关于扩展 ASP.NET 验证器的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET MVC 3 应用程序中扩展 Windows 身份验证

ASP.NET 文件上传 - 验证

ASP.NET Web API模型验证以及异常处理方式

ASP.NET Core 文件上传 之 文件签名验证

ASP.NET Windows 身份验证向应用程序返回错误的用户

当页面验证失败时,如何禁用我的 ASP.NET AJAX ConfirmButtonExtender?