2011-02-09 55 views
7

Tôi đã được tinkering với các tính năng xác nhận phía khách hàng trong ASP.net MVC sau khi đọc ScottGU's blog post về chủ đề này. Việc sử dụng thuộc tính System.Componentmodel.DataAnnotations khá dễ dàng như sau:asp.net mvc phía khách hàng xác nhận

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

... nhưng điều gì sẽ xảy ra nếu bạn cần một thứ phức tạp hơn một chút. Điều gì sẽ xảy ra nếu bạn có một lớp Địa chỉ với trường Mã Bưu điện và Mã Quốc gia. Bạn sẽ muốn xác thực mã bưu chính dựa vào một regex khác nhau cho từng quốc gia. [0-9] {5} làm việc cho Hoa Kỳ, nhưng bạn cần một cái khác cho Canada.

Tôi nhận được điều đó bằng cách lăn lớp ValidationService của riêng tôi để lấy thuộc tính ModelState của bộ điều khiển và xác thực nó cho phù hợp. Điều này hoạt động tốt ở phía máy chủ nhưng không hoạt động với tính năng xác thực phía máy khách mới lạ mắt.

Trong biểu mẫu web, tôi sẽ sử dụng các điều khiển phát tán javascript như RequiredFieldValidator hoặc CompareValidator cho những thứ dễ dàng và sau đó sử dụng CustomValidator cho các quy tắc phức tạp. Bằng cách này, tôi có tất cả logic xác nhận của mình ở một nơi và tôi nhận được lợi ích của việc xác thực javascript nhanh chóng cho các công cụ đơn giản (90% thời gian) trong khi tôi vẫn nhận được tính bảo mật của xác thực phía máy chủ.

Cách tiếp cận tương đương trong MVC là gì?

+0

Tôi không chắc chắn về điều này nhưng tôi nghĩ rằng bạn khá nhiều phải tung ra xác nhận khách hàng của riêng bạn cho những thứ tùy chỉnh như thế. Có thể xem xét Jquery Validation-http: //docs.jquery.com/Plugins/validation – Vishal

+0

Phiên bản ASP.NET MVC nào bạn đang nhắm mục tiêu? –

Trả lời

1

Tôi vừa thấy một cái gì đó về giao diện IValidatableObject trong MVC 3 và tôi sẽ thử.

1

Xác định thuộc tính xác thực của riêng bạn từ ValidationAttribute và áp dụng logic cho phù hợp. Trong MVC 2, để thực hiện xác thực thuộc tính dựa trên giá trị của thuộc tính khác, điều này phải được thực hiện bên trong Trình xác thực mà bạn đăng ký sử dụng với thuộc tính xác thực tùy chỉnh bằng cách sử dụng (giả sử bạn sử dụng DataAnnotationsModelValidatorProvider)

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

vì trong thuộc tính xác thực, bạn chỉ có quyền truy cập vào giá trị thuộc tính mà thuộc tính đó bị ràng buộc chứ không phải mô hình.

Hãy xem MVC FoolProof Validation để xem cách tiếp cận này được thực hiện.

+0

Điều đó có tự động được chọn trong quá trình xác thực phía khách hàng của hộp không? – CRice

+0

@CRice - nếu xuất phát từ một trong các thuộc tính trong System.ComponentModel.DataAnnotations, thì phía máy khách sẽ được xử lý cho bạn. Nếu xác định attirbute xác nhận của riêng bạn, bạn cũng sẽ cần phải chăm sóc bằng văn bản phía khách hàng logic. Giả sử việc sử dụng jQuery của bạn xác nhận hợp lệ, bạn sẽ thêm một hàm validator để gọi đến jQuery validation keyed bởi một chuỗi để sử dụng khi quy tắc hợp lệ khớp với khóa. –

+0

Làm thế nào để hệ thống biết javascript cần xuất để sử dụng để xác thực bất kỳ lớp tùy chỉnh nào kế thừa từ System.ComponentModel.DataAnnotations.ValidationAttribute? – CRice

7

Chỉnh sửa: Giả sử bạn đang sử dụng MVC 3. Thật không may, mã của tôi nằm trong VB.NET vì đó là những gì tôi phải sử dụng tại nơi làm việc.

Để làm cho mọi thứ hoạt động độc đáo với tính năng xác thực không phô trương mới, có một vài điều bạn phải làm. Tôi đã cung cấp cho họ một vài tuần trước.

Trước tiên, hãy tạo lớp thuộc tính tùy chỉnh kế thừa từ ValidationAttribute. Lớp thuộc tính RequiredIf đơn giản dưới đây:

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 

Tiếp theo, bạn cần triển khai lớp xác thực. Lớp này chịu trách nhiệm cho phép MVC biết các quy tắc xác thực máy khách được yêu cầu cho thư viện xác nhận không phô trương hoạt động.

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 

Bây giờ bạn có thể đăng ký tất cả mọi thứ trong phương pháp bắt đầu áp dụng Global.asax:

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

này giúp bạn 90% con đường đó.Bây giờ bạn chỉ cần nói với JQuery xác nhận và xác nhận lớp không phô trương của MS làm thế nào để đọc các thuộc tính mới của bạn:

/// <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)); 

Hope this helps, đây là một nỗi đau thực sự để làm việc.

+0

Giải thích tốt, có ý nghĩa khi nhìn thấy nó từ đầu đến cuối – CRice

+0

Cảm ơn, @CRice. Hy vọng rằng điều này sẽ giúp ai đó khác. Tôi đã có thể giết chết một cái gì đó như thế này trong khi MVC 3 là trong phiên bản beta, nhưng nó đã được tất cả trong bit và miếng. –

+0

@SheaDaniels "Thật không may mã của tôi là trong VB.NET vì đó là những gì tôi phải sử dụng tại nơi làm việc." Thats lý do đủ cho một công việc mới! – Elisabeth

3

ScottGu đã tweet sáng nay về cách Pluralsight có miễn phí MVC 3 training trong 48 giờ tới. Họ có video hiển thị cách thực hiện xác thực tùy chỉnh này. Các video có liên quan nằm trong 'Mô hình trong ASP.NET MVC 3.0', cụ thể là 'Thuộc tính xác thực tùy chỉnh' và 'Mô hình tự xác thực'.

+0

Video tuyệt vời. Và tiếp thị tuyệt vời để cung cấp cho họ đi trong hai ngày. –

+0

+1 Video tuyệt vời. Tôi vừa đăng ký bản dùng thử miễn phí và xem "Xác thực ứng dụng khách tùy chỉnh". Nó khá kỹ lưỡng và đã giúp. Tôi hiện đang dùng thử 10 ngày và có thể xem thêm một vài lần nữa trước khi hết. Họ cung cấp một dịch vụ tốt. – Aaron

0

Tôi nghĩ rằng giải pháp cho vấn đề của bạn là System.ComponentModel.DataAnnotations trong MVC

Đối với logic phức tạp, bạn có thể thực hiện logic của riêng bạn. Nó rất dễ. Có một cái nhìn để tùy vào liên kết này: http://msdn.microsoft.com/en-us/library/cc668224.aspx

Đối với điều cơ bản làm cho bạn Xem binded với mô hình lớp và thêm thuộc tính trên tài sản ... Giống như

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

Xem mạnh gõ với Class này

Các vấn đề liên quan