我注意到在创建自定义验证属性时,我的验证仅在本机MVC数据注释触发后触发。有什么办法可以“同时”发射吗?
为了表明我的意思,假装我有这样的形式:
FirstName: <FirstName Textbox>
LastName: <LastName TextBox>
Zip: <Zip TextBox>
所以我对所有3都有一个[Required]注释,但另外,对于Zip属性,我有一个自定义属性。如果用户没有输入名字或姓氏,但是输入了无效的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 Validator(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数据注释做到这一点,但是我希望将来推出自己的自定义验证器。
谢谢!
答案 0 :(得分: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.";
}
}
并在Global.asax中:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(ZipAttribute), typeof(RegularExpressionAttributeAdapter));
这样做有什么好处,你可以指定你自己的默认错误信息!
奇怪的是,一些验证属性(StringLength,Range,RegularExpression)仍然使用AttributeAdapters,而其他属性(如CompareAttribute)使用IClientValidatable。
祝你好运!答案 1 :(得分:3)
发生这种情况的原因是您启用了不显眼的客户端验证,并且您的自定义验证属性未实现IClientValidatable
。它需要实现这一点,以允许呈现作为客户端验证过程一部分所需的data-*
属性。您还需要提供一个客户端正则表达式验证例程,它反映了服务器端验证。
如果你想走简单路线,请在web.config中禁用客户端验证和不引人注目的javascript,如下所示:
<appSettings>
<add key="ClientValidationEnabled" value="false"/>
<add key="UnobtrusiveJavaScriptEnabled" value="false"/>
</appSettings>
您的页面应该按照您的预期运行,但现在所有验证都将在服务器上进行。如果你想让不引人注目的客户端验证成为一种旋风,那么这些链接应该会有所帮助。
答案 2 :(得分: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._-]+@@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
return emailPattern.test(value);
});
jQuery.validator.unobtrusive.adapters.addBool("validemail");
});