asp.net mvc客户端验证

时间:2011-02-09 22:52:15

标签: asp.net asp.net-mvc

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

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

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

我通过滚动自己的ValidationService类来解决这个问题,该类接受控制器的ModelState属性并相应地验证它。这在服务器端运行良好,但不适用于花哨的新客户端验证。

在Webforms中,我会使用像JavaScript一样的控件,如RequiredFieldValidator或CompareValidator,然后使用CustomValidator来处理复杂的规则。这样我就可以在一个地方拥有所有验证逻辑,并且我可以获得快速javascript验证的好处(90%的时间),同时我仍然可以获得服务器端验证的安全性作为支持。

MVC中的等效方法是什么?

5 个答案:

答案 0 :(得分:7)

编辑:这假设您正在使用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));

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

答案 1 :(得分:3)

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

答案 2 :(得分:1)

我刚看到MVC 3中有关IValidatableObject接口的内容,我会试一试。

答案 3 :(得分:1)

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

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

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

查看 MVC FoolProof Validation ,看看这种方法是如何完成的。

答案 4 :(得分:0)

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

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

对于基本的东西,你可以使用Model Class查看Binded并在属性的顶部添加属性... 像

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

使用此类

强烈查看