Supponiamo di avere il seguente modello:
[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
public bool IsChecked { get; set; }
}
con il seguente validatore:
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.IsChecked).Equal(true).WithMessage("Please check this checkbox");
}
}
e un controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
con una corrispondente vista:
@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>
}
e in Global.asax
aver registrato il modello di validazione fornitore validator fluente:
FluentValidationModelValidatorProvider.Configure();
Finora abbiamo lato server convalida fino e fine corsa. Quello è buono. Questa è sempre la prima parte che dobbiamo impostare. Ho visto persone che si concentrano troppo sulla convalida del lato client che dimenticano di eseguire la convalida lato server e quando disabiliti javascript (o peggio ancora se inciampi su un utente con cattive intenzioni), beh, le cose brutte accadono. Finora siamo fiduciosi perché sappiamo che anche se qualcosa si fa rovinare sul client, il nostro dominio è protetto con la convalida lato server.
Quindi cerchiamo di ora prendersi cura per la convalida del client. Out of the box FluentValidation.NET supporta la convalida automatica del client per il validatore EqualTo
ma durante il confronto con un altro valore di proprietà che è l'equivalente dell'annotazione dati [Compare]
.
Ma nel nostro caso ci confrontiamo con un valore fisso. Quindi non riusciamo a far uscire la situazione dal lato client. E quando non prendiamo qualcosa fuori dalla scatola, dobbiamo metterlo nella scatola.
Dunque iniziamo definendo un FluentValidationPropertyValidator personalizzato:
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;
}
}
che ci accingiamo a registrare in Application_Start
:
FluentValidationModelValidatorProvider.Configure(provider =>
{
provider.AddImplicitRequiredValidator = false;
provider.Add(typeof(EqualValidator), (metadata, context, description, validator) => new EqualToValueFluentValidationPropertyValidator(metadata, context, description, validator));
});
Finora abbiamo associato il nostro FluentValidationPropertyValidator personalizzato con l'EqualValidator.
L'ultima parte è quello di scrivere un adattatore personalizzato:
(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);
E questo è praticamente. Tutto ciò che rimane è quello di includere gli script client:
<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>
Grazie, è grande. Ma ho dovuto modificare le righe con: [restituire value.toLowerCase() === ...] a: [restituire params.valuetocompare.toLowerCase() === ...] – cryss
Vedere http: // stackoverflow. it/questions/21345078/fluentvalidation-validate-checkbox-and-password-on-the-client-with-equalvalidato per un problema quando si ha un altro ugual validator presente (ad es. conferma password) insieme a una soluzione. – Ted