Я создаю специальный валидатор для моего приложения MVC4. Чтобы все было просто и сосредоточиться на этом вопросе, скажите, что я переопределяю проверку сервера класса RequiredAttribute
и проверку на стороне клиента:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MyRequiredAttribute: ValidationAttribute, IClientValidatable
{
public MyRequiredAttribute() : base("The {0} field is required.")
{
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
{
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRequiredRule(ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()));
}
}
Чтобы проверить это, у меня есть очень простой контроллер:
public class TestController : Controller
{
public ActionResult Index()
{
return View(new MyThing {Value = "whatever"});
}
[HttpPost]
public ActionResult Index(MyThing thing)
{
if (ModelState.IsValid)
{
return Content("Good choice!");
}
return View(thing);
}
}
и очень простая модель:
public class MyThing
{
[MyRequired]
public string Value { get; set; }
[Required]
public string OtherValue { get; set; }
}
и, наконец, индекс:
@model MyThing
@{
Layout = "~/Views/Shared/_LayoutWithAllTheAppropriateValidationScripts.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
@using(Html.BeginForm()){
@Html.ValidationSummary(true)
@Html.EditorForModel()
<input type="submit" value="submit"/>
}
</div>
</body>
</html>
Вы заметите, что у меня есть Value
который украшен пользовательским MyRequiredAttribute
и OtherValue
который украшен стандартным RequiredAttribute
.
Обе из них прекрасно работают на стороне сервера и возвращают соответствующие сообщения проверки при обратной передаче, но только клиентский RequiredAttribute
работает на стороне клиента. Поскольку я использую ModelClientValidationRequiredRule
вместо ModelClientValidationRule
с настраиваемым свойством ValidationType
я предполагаю, что никакие настраиваемые правила проверки клиентов не должны определяться, но я не знаю этого точно, потому что я не смог получить это далеко. Отладчик никогда не ломается внутри метода GetClientValidationRules
и элемент ввода html, сгенерированный для свойства Value
в моей модели, не имеет атрибутов data-val-required
и data-val
как и поле OtherValue
, которое я предполагаю, является тем, что Метод GetClientValidationRules
отвечает за выполнение.
Мне, должно быть, здесь что-то не хватает... что это?
Это оказалось ошибкой пользователя, но я все равно отправлю решение в надежде, что это поможет кому-то еще с подобной проблемой в будущем.
Код в исходном вопросе находится в отдельной сборке из проекта MVC, который его использует. Недавно проект MVC был повышен с MVC3 до MVC4. Я выполнил инструкции, предоставленные Microsoft по вопросам модернизации, или, как я думал. Я пропустил одну часть в файле web.config:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
Это говорит о проекте MVC, как играть хорошо с сборками, от которых зависит, которые были скомпилированы со ссылкой на более раннюю версию сборки System.Web.Mvc
. После обновления моего проекта MVC он ссылался на System.Web.Mvc
v4 и мой "Common" (где расширен расширенный ValidatorAttribute
реализующий IClientValidatable
), на который ссылается v3. Конфигурация выше должна была быть обновлена с обновлением, но она пропустила. Проблема не проявлялась ни в каком другом ключе, кроме проблемы проверки на стороне клиента, изложенной в исходном вопросе.
Оскорбительная линия здесь была
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0"/>
которые должны были быть
<bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
которая фиксировала проблему.
Добавьте это в свой Global.asax:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MyRequiredAttribute), typeof(RequiredAttributeAdapter));
Это должно решить проблему проверки на стороне клиента.