Порядок проверки при использовании аннотаций и пользовательских атрибутов - PullRequest
6 голосов
/ 13 мая 2011

Я заметил, что при создании пользовательского атрибута проверки моя проверка запускается только после срабатывания собственных аннотаций данных MVC. Есть ли способ, которым он мог выстрелить "одновременно"?

Чтобы показать, что я имею в виду, представьте, что у меня есть эта форма:

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

Итак, у меня есть аннотация [Требуется] для всех 3, но кроме того, для свойства 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, но я собираюсь развернуть свои собственные валидаторы в будущем.

Спасибо!

Ответы [ 3 ]

4 голосов
/ 13 мая 2011

Есть лучшее решение, чем отключение ненавязчивой проверки клиента.

Поскольку вы сопоставляете только регулярное выражение, вместо этого вы можете попробовать сделать это (будет работать с проверкой 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.

Удачи!

3 голосов
/ 14 мая 2011

Вам необходимо добавить версию проверки 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");
});
3 голосов
/ 13 мая 2011

Причина, по которой это происходит, в том, что у вас включена ненавязчивая проверка на стороне клиента, а ваш пользовательский атрибут проверки не реализует IClientValidatable. Это должно было бы реализовать это, чтобы позволить рендеринг data-* атрибутов, которые необходимы как часть процесса проверки клиента. Вам также потребуется предоставить процедуру проверки регулярных выражений на стороне клиента, которая отражает проверку на стороне сервера.

Если вы хотите пойти по простому пути, отключите проверку на стороне клиента и ненавязчивый JavaScript в web.config, например:

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

Ваша страница должна вести себя так, как вы ожидаете, но теперь вся ваша проверка будет происходить на сервере. Если вы хотите, чтобы ненавязчивая валидация на стороне клиента прошла мимо, эти ссылки должны быть полезны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...