Ответ 1
Предположим, что у вас есть следующая модель:
[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
public bool IsChecked { get; set; }
}
со следующим валидатором:
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.IsChecked).Equal(true).WithMessage("Please check this checkbox");
}
}
и контроллер:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
с соответствующим представлением:
@model MyViewModel
@using (Html.BeginForm())
{
@Html.LabelFor(x => x.IsChecked)
@Html.CheckBoxFor(x => x.IsChecked)
@Html.ValidationMessageFor(x => x.IsChecked)
<button type="submit">OK</button>
}
а в Global.asax
вы зарегистрировали надежного поставщика проверки достоверности модели проверки:
FluentValidationModelValidatorProvider.Configure();
До сих пор мы проверяем и выполняем проверку на стороне сервера. Это хорошо. Это всегда первая часть, которую мы должны настроить. Я видел, что люди слишком много внимания уделяют проверке на стороне клиента, что они забывают о проверке на стороне сервера и когда вы отключите javascript (или, что еще хуже, если вы наткнетесь на пользователя с плохими намерениями), хорошо, что это происходит. До сих пор мы уверены, что знаем, что даже если что-то навязывается клиенту, наш домен защищен проверкой на стороне сервера.
Итак, давайте теперь позаботимся о проверке клиента. Из коробки FluentValidation.NET поддерживает автоматическую проверку клиента для валидатора EqualTo
, но при сравнении с другим значением свойства, которое является эквивалентом аннотации данных [Compare]
.
Но в нашем случае мы сравниваем с фиксированным значением. Таким образом, мы не освобождаем клиентскую сторону из коробки. И когда мы не получаем что-то из коробки, нам нужно положить его в коробку.
Итак, мы начинаем с определения пользовательского FluentValidationPropertyValidator:
public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
: base(metadata, controllerContext, rule, validator)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
if (!this.ShouldGenerateClientSideRules())
{
yield break;
}
var validator = (EqualValidator)Validator;
var errorMessage = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ValueToCompare", validator.ValueToCompare)
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule();
rule.ErrorMessage = errorMessage;
rule.ValidationType = "equaltovalue";
rule.ValidationParameters["valuetocompare"] = validator.ValueToCompare;
yield return rule;
}
}
что мы будем регистрироваться в Application_Start
:
FluentValidationModelValidatorProvider.Configure(provider =>
{
provider.AddImplicitRequiredValidator = false;
provider.Add(typeof(EqualValidator), (metadata, context, description, validator) => new EqualToValueFluentValidationPropertyValidator(metadata, context, description, validator));
});
До сих пор мы связали наш собственный FluentValidationPropertyValidator с EqualValidator.
Последняя часть предназначена для написания пользовательского адаптера:
(function ($) {
$.validator.unobtrusive.adapters.add('equaltovalue', ['valuetocompare'], function (options) {
options.rules['equaltovalue'] = options.params;
if (options.message != null) {
options.messages['equaltovalue'] = options.message;
}
});
$.validator.addMethod('equaltovalue', function (value, element, params) {
if ($(element).is(':checkbox')) {
if ($(element).is(':checked')) {
return value.toLowerCase() === 'true';
} else {
return value.toLowerCase() === 'false';
}
}
return params.valuetocompare.toLowerCase() === value.toLowerCase();
});
})(jQuery);
И это в значительной степени. Осталось оставить клиентские скрипты:
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/customadapter.js")" type="text/javascript"></script>