2011-05-12 97 views
6

我注意到,在創建自定義驗證屬性時,我的驗證僅在本機MVC數據註釋激發後觸發。有什麼辦法可以「同時」發射?使用註釋和自定義屬性時的驗證順序

爲了說明我的意思,假裝我有這樣的形式:

FirstName: <FirstName Textbox> 
LastName: <LastName TextBox> 
Zip: <Zip TextBox> 

所以我有一個[必填]註釋爲所有3,但除此之外,對於郵編財產,我有一個自定義屬性。如果用戶不輸入名字或姓氏,但輸入了一個無效的Zip(我的屬性應該驗證這一點),那麼所有三個都應該有一個錯誤信息 - 但是沒有。 firstName和lastName只有一個錯誤。

這是代碼:

Person.cs:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.ComponentModel.DataAnnotations; 

// My validator 
using MvcApplication3.Extensions.Validation; 

namespace MvcApplication3.Models 
{ 
    public class Person 
    { 
    [Required(ErrorMessage="Field required!")] 
    public string firstName{get;set;} 

    [Required(ErrorMessage="Field required!")] 
    public string lastName { get; set; }  

    [Zip(ErrorMessage="You gotta put in a valid zip code")] 
    [Required(ErrorMessage="Field required!")] 
    public string zipCode { get; set; }  
    } 
} 

控制器:

[HttpPost] 
public ActionResult Index(FormCollection form, Person person) 
{ 
    return View(person); 
} 

檢視:

@model MvcApplication3.Models.Person 
@{ 
    ViewBag.Title = "Person"; 
    Layout = "~/Views/Shared/_Layout.cshtml";  

} 
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 

<h2> 
    Testing Form: @Model.firstName 
</h2> 
<hr /> 

@{Html.EnableClientValidation();} 

@using (Html.BeginForm()) 
{ 
    @Html.LabelFor(model => model.firstName) 
    @Html.TextBoxFor(model => model.firstName) 
    @Html.ValidationMessageFor(model=>model.firstName) 

    <br /><br /> 
    @Html.LabelFor(model => model.lastName) 
    @Html.TextBoxFor(model => model.lastName) 
    @Html.ValidationMessageFor(model=>model.lastName) 

    <br /><br /> 
    @Html.LabelFor(model => model.zipCode) 
    @Html.TextBoxFor(model => model.zipCode) 
    @Html.ValidationMessageFor(model=>model.zipCode)  

    <br /><br /> 
    <input type="submit" value="Submit" /> 
} 

郵編驗證器(Zip.cs):

public class ZipAttribute : ValidationAttribute 
    { 
    public override bool IsValid(object value) 
    { 
     bool foundMatch = false; 
     try 
     { 
     foundMatch = Regex.IsMatch(value.ToString(), "\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z"); 
     } 
     catch (ArgumentException ex) 
     { 
     // Syntax error in the regular expression 
     } 
     return foundMatch; 
    } 
    } 

此外,我知道我可以使用Regexp數據註釋來做到這一點,但我期待在未來推出自己的自定義驗證器。

謝謝!

回答

3

您需要添加一個驗證的Javascript版本,該驗證將運行客戶端(或禁用客戶端驗證,但這有點麻煩)。

有建立自定義的驗證電子郵件地址在這裏的一個示例:

http://thepursuitofalife.com/asp-net-mvc-3-unobtrusive-javascript-validation-with-custom-validators/

這顯示了C#代碼(這包括設置javascript函數的名稱,將做客戶端的驗證),以及javascript「validemail」例程。

public class ValidEmailAttribute : ValidationAttribute, IClientValidatable 
{ 
    // ... 

    public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     yield return new ModelClientValidationRule 
     { 
      ErrorMessage = FormatErrorMessage(metadata.DisplayName), 
      ValidationType = "validemail" 
     }; 
    } 
} 

而且JS:

$(function() { 
    jQuery.validator.addMethod("validemail", function (value, element, param) { 
     var emailPattern = /^[a-zA-Z0-9._-][email protected]@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; 
     return emailPattern.test(value); 
    }); 
    jQuery.validator.unobtrusive.adapters.addBool("validemail"); 
}); 
3

發生這種情況的原因是因爲您已啓用不引人注意的客戶端驗證,並且您的自定義驗證屬性未實現IClientValidatable。它需要實現這一點,以允許呈現data-*屬性,這些屬性是客戶端驗證過程的一部分。您還需要提供一個客戶端正則表達式驗證例程,以反映您的服務器端驗證。

如果你想要去的輕鬆路線,禁用客戶端驗證和不顯眼的JavaScript在web.config中像這樣:

<appSettings> 
    <add key="ClientValidationEnabled" value="false"/> 
    <add key="UnobtrusiveJavaScriptEnabled" value="false"/> 
</appSettings> 

那麼你的頁面應該表現你會怎麼想到的,但所有的審定會,現在發生在服務器上。如果你想給不引人注目的客戶端驗證一個旋風,那麼這些鏈接應該是有幫助的。

+0

感謝您的反饋意見。所以我幾乎必須編寫與我的驗證器相匹配的等效JavaScript代碼? – SaltProgrammer 2011-05-13 19:55:18

+0

不幸的是,你做 - 看到我的答案下面的鏈接。你可以用Script#做這個,但是沒有什麼內置的將你的C#轉換成Javascript(但這就是Script#打算做的事情:-)) – 2011-05-14 09:08:16

4

有比禁用不顯眼的客戶端驗證一個更好的解決方案。

既然你只匹配正則表達式,你可以嘗試,而不是做這個(將與JavaScript驗證工作):

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 
public class ZipAttribute : System.ComponentModel.DataAnnotations.RegularExpressionAttribute 
{ 
    public ZipAttribute() : base("\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z") 
    { 
     ErrorMessage = "Invalid ZIP code."; 
    } 
} 

,並在全球。asax:

 DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(ZipAttribute), typeof(RegularExpressionAttributeAdapter)); 

這樣做的好處是,您可以指定您自己的默認錯誤消息!

奇怪的是,某些驗證屬性(StringLength,Range,RegularExpression)仍然使用AttributeAdapters,而其他屬性(如CompareAttribute)使用IClientValidatable。

祝你好運!

+0

感謝您的反饋。 Yeap,這就是我在找的東西,但我想用自定義的C#邏輯來驗證,而不是正則表達式。 而不是從RegularExpressionAttribute繼承,我可以繼承一些我可以把我自己的驗證邏輯代碼放在哪裏? – SaltProgrammer 2011-05-13 19:57:12

+0

如果您打算使用自定義代碼,則仍然需要編寫客戶端JavaScript。沒有將C#代碼自動轉換爲Javascript代碼。你必須自己去做。 – 2011-05-16 04:48:38

+1

爲什麼有些屬性使用IClientValidatable而有些屬性不是因爲那些隨.NET框架(必需的和朋友)一起提供的屬性,他們不知道MVC。 IClientValidatable接口是一個MVC接口,而不是.NET接口。 CompareAttribute與MVC一起提供,所以它知道(並且可以實現)IClientValidatable。 – 2011-05-16 04:49:41