【问题标题】:asp.net mvc client side validationasp.net mvc 客户端验证
【发布时间】:2011-02-09 22:52:15
【问题描述】:

在阅读了有关该主题的ScottGU's blog post 之后,我一直在修改 ASP.net MVC 中的客户端验证功能。像这样使用 System.Componentmodel.DataAnnotations 属性非常容易:

    [Required(ErrorMessage = "You must specify a reason")]
    public string ReasonText { get; set; }

...但是如果您需要一些更复杂的东西会发生什么。如果您有一个带有 PostalCode 和 CountryCode 字段的 Address 类怎么办。您可能希望针对每个国家/地区的不同正则表达式验证邮政编码。 [0-9]{5} 适用于美国,但您需要另一种适用于加拿大。

我通过滚动我自己的 ValidationService 类来解决这个问题,该类采用控制器的 ModelState 属性并相应地对其进行验证。这在服务器端工作得很好,但不适用于花哨的新客户端验证。

在 Webforms 中,我会使用像RequiredFieldValidator 或CompareValidator 这样的发出javascript 的控件来处理简单的事情,然后使用CustomValidator 来处理复杂的规则。通过这种方式,我将所有验证逻辑集中在一个地方,并且我可以从快速的 javascript 验证中受益(90% 的时间),同时我仍然可以获得服务器端验证的安全性作为支持。

MVC 中的等效方法是什么?

【问题讨论】:

  • 对此我不确定,但我认为您几乎必须针对此类自定义内容推出自己的客户端验证。也许看看 Jquery Validation-docs.jquery.com/Plugins/validation
  • 您的目标是哪个版本的 ASP.NET MVC?

标签: asp.net asp.net-mvc


【解决方案1】:

编辑:假设您使用的是 MVC 3。不幸的是,我的代码在 VB.NET 中,因为这是我在工作中必须使用的。

为了使新的不显眼的验证能够很好地工作,您需要做一些事情。几周前我通过了它们。

首先,创建一个继承自ValidationAttribute 的自定义属性类。一个简单的RequiredIf属性类如下:

Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations

<AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)> _
Public NotInheritable Class RequiredIfAttribute
    Inherits ValidationAttribute

    Private Const    _defaultErrorMessage As String = "'{0}' is required."
    Private ReadOnly _dependentProperty   As String
    Private ReadOnly _targetValues        As Object()

    Public Sub New(dependentProperty As String, targetValues As Object())

        MyBase.New(_defaultErrorMessage)

        _dependentProperty = dependentProperty
        _targetValues      = targetValues

    End Sub

    Public Sub New(dependentProperty As String, targetValues As Object(), errorMessage As String)

        MyBase.New(errorMessage)

        _dependentProperty = dependentProperty
        _targetValues      = targetValues

    End Sub

    Public ReadOnly Property DependentProperty() As String
        Get
            Return _dependentProperty
        End Get
    End Property

    Public ReadOnly Property TargetValues() As Object()
        Get
            Return _targetValues
        End Get
    End Property

    Public Overrides Function FormatErrorMessage(name As String) As String

        Return String.Format(Globalization.CultureInfo.CurrentUICulture, ErrorMessageString, name)

    End Function

    Protected Overrides Function IsValid(value As Object, context As ValidationContext) As ValidationResult

        ' find the other property we need to compare with using reflection
        Dim propertyValue = context.ObjectType.GetProperty(DependentProperty).GetValue(context.ObjectInstance, Nothing).ToString()

        Dim match = TargetValues.SingleOrDefault(Function(t) t.ToString().ToLower() = propertyValue.ToLower())

        If match IsNot Nothing AndAlso value Is Nothing Then
            Return New ValidationResult(FormatErrorMessage(context.DisplayName))
        End If

        Return Nothing

    End Function

End Class

接下来,您需要实现一个验证器类。这个类负责让 MVC 知道非侵入式验证库工作所需的客户端验证规则。

Public Class RequiredIfValidator
    Inherits DataAnnotationsModelValidator(Of RequiredIfAttribute)

    Public Sub New(metaData As ModelMetadata, context As ControllerContext, attribute As RequiredIfAttribute)

        MyBase.New(metaData, context, attribute)

    End Sub

    Public Overrides Function GetClientValidationRules() As IEnumerable(Of ModelClientValidationRule)

        Dim rule As New ModelClientValidationRule() With {.ErrorMessage = ErrorMessage,
                                                          .ValidationType = "requiredif"}

        rule.ValidationParameters("dependentproperty") = Attribute.DependentProperty.Replace("."c, HtmlHelper.IdAttributeDotReplacement)

        Dim first       As Boolean = True
        Dim arrayString As New StringBuilder()

        For Each param In Attribute.TargetValues
            If first Then
                first = False
            Else
                arrayString.Append(",")
            End If
            arrayString.Append(param.ToString())
        Next

        rule.ValidationParameters("targetvalues") = arrayString.ToString()

        Return New ModelClientValidationRule() {rule}

    End Function

End Class

现在你可以在Global.asax的应用程序启动方法中注册一切:

DataAnnotationsModelValidatorProvider.RegisterAdapter(GetType(RequiredIfAttribute), GetType(RequiredIfValidator))

这可以让您完成 90% 的任务。现在你只需要告诉 JQuery validate 和 MS 的不显眼的验证层如何读取你的新属性:

/// <reference path="jquery-1.4.1-vsdoc.js" />
/// <reference path="jquery.validate-vsdoc.js" />

/* javascript for custom unobtrusive validation
   ==================================================== */

(function ($) {

    // this adds the custom "requiredif" validator to the jQuery validate plugin
    $.validator.addMethod('requiredif',
                          function (value, element, params) {

                              // the "value" variable must not be empty if the dependent value matches
                              // one of the target values
                              var dependentVal = $('#' + params['dependentProperty']).val().trim().toLowerCase();
                              var targetValues = params['targetValues'].split(',');

                              // loop through all target values
                              for (i = 0; i < targetValues.length; i++) {
                                  if (dependentVal == targetValues[i].toLowerCase()) {
                                      return $.trim(value).length > 0;
                                  }
                              }

                              return true;
                          },
                          'not used');

    // this tells the MS unobtrusive validation layer how to read the
    // HTML 5 attributes that are output for the custom "requiredif" validator
    $.validator.unobtrusive.adapters.add('requiredif', ['dependentProperty', 'targetValues'], function (options) {

        options.rules['requiredif'] = options.params;
        if (options.message) {
            options.messages['requiredif'] = options.message;
        }

    });

} (jQuery));

希望这会有所帮助,开始工作真的很痛苦。

【讨论】:

  • 很好的解释,从头到尾看都很有意义
  • 谢谢,@CRice。希望这对其他人有帮助。当 MVC 3 处于测试阶段时,我会因为这样的事情而杀人,但这一切都是零碎的。
  • @SheaDaniels “不幸的是,我的代码在 VB.NET 中,因为这是我在工作中必须使用的。”这足以成为一份新工作的理由!
【解决方案2】:

ScottGu 今天早上在推特上发布了 Pluralsight 如何在接下来的 48 小时内免费使用MVC 3 training。他们有一个视频展示了如何进行这种自定义验证。相关视频位于“ASP.NET MVC 3.0 中的模型”下,特别是“自定义验证属性”和“自我验证模型”。

【讨论】:

  • 很棒的视频。以及为期两天的精彩营销活动。
  • +1 很棒的视频。我刚刚注册了免费试用版并观看了“自定义客户端验证”。它非常彻底并且有所帮助。我现在正在进行 10 天的试用期,可能会在试用期结束前再看一些。他们提供良好的服务。
【解决方案3】:

我刚刚在 MVC 3 中看到了有关 IValidatableObject 接口的一些信息,我将尝试一下。

【讨论】:

    【解决方案4】:

    ValidationAttribute 派生您自己的验证属性并相应地应用逻辑。在 MVC 2 中,为了根据另一个属性的值对属性进行验证,这必须在您注册以与自定义验证属性一起使用的 Validator 内完成(假设您使用 DataAnnotationsModelValidatorProvider

    DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(ValidationAttribute), typeof(ValidationValidator)); 
    

    因为在验证属性中,您只能访问属性绑定的属性值,而不能访问模型。

    看看 MVC FoolProof Validation 看看这个方法是如何完成的。

    【讨论】:

    • 那会在开箱即用的客户端验证中自动获取吗?
    • @CRice - 如果派生自 System.ComponentModel.DataAnnotations 中的属性之一,则将为您处理客户端。如果定义自己的验证属性,您还需要自己编写客户端逻辑。假设您使用 jQuery 验证,您将添加一个验证器函数来调用由字符串键入的 jQuery 验证,以便在验证规则与键匹配时使用。
    • 系统如何知道要输出什么 javascript 来验证从 System.ComponentModel.DataAnnotations.ValidationAttribute 继承的任何自定义类?
    • @CRice- 你的验证器注册到你的验证属性有一个方法叫做GetClientValidationRules。在此方法中,您在返回的 ModelClientValidationRule 类型上为 ValidationType 分配一个字符串值,该类型指示要在客户端使用的规则名称。
    【解决方案5】:

    我认为您的问题的解决方案是 MVC 中的 System.ComponentModel.DataAnnotations

    对于复杂的逻辑,您可以实现自己的逻辑。它很容易。 看看这个链接上的定制:http://msdn.microsoft.com/en-us/library/cc668224.aspx

    对于基本的事情,让您查看与模型类绑定并在属性顶部添加属性... 喜欢

    public class CustomerSearchDE
    {
        [StringLength(2, ErrorMessageResourceType = typeof(Translation), ErrorMessageResourceName = MessageConstants.conCompanyNumberMaxLength)]
        public string CompanyNumber { get; set; }
     }
    

    使用此类查看强类型

    【讨论】:

      猜你喜欢
      • 2010-09-14
      • 2014-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-12
      • 2011-02-08
      • 1970-01-01
      相关资源
      最近更新 更多