FluentValidation Validate checkbox and password on the client with EqualValidator

孤街醉人 提交于 2019-12-11 10:34:51

问题


I implemented the code below to have a way to validate a checkbox unobtrusively found this code posted by Darin Dimitrov. It works really well for the checkbox, but it does not work if you also have password and confirm password validated with the EqualValidator. I wonder if the custom Validator can be changed to take the checkbox and password validation into account. Or do I need to write a custom Validator for the password?

Model

[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
    public bool IsChecked { get; set; }
}

Validator

public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
    public MyViewModelValidator()
    {
        RuleFor(x => x.IsChecked).Equal(true).WithMessage("Please check this checkbox");
    }
}

Controller

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

View

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.LabelFor(x => x.IsChecked)
    @Html.CheckBoxFor(x => x.IsChecked)
    @Html.ValidationMessageFor(x => x.IsChecked)

    @Html.LabelFor(model => model.Password, new { }, ":")
    @Html.EditorFor(model => model.Password)
    @Html.ValidationMessageFor(model => model.Password)

    @Html.LabelFor(model => model.ConfirmPassword, new { }, ":")
    @Html.EditorFor(model => model.ConfirmPassword)
    @Html.ValidationMessageFor(model => model.ConfirmPassword)

    <button type="submit">OK</button>
}

Custom 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;
    }
}

Global.asax

FluentValidationModelValidatorProvider.Configure(provider =>
{
    provider.AddImplicitRequiredValidator = false;
    provider.Add(typeof(EqualValidator), (metadata, context, description, validator) => new EqualToValueFluentValidationPropertyValidator(metadata, context, description, validator));
});

jQuery

(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>

回答1:


I know this is a few months old, but I was having the same problem. I posted a solution in Darin's original thread -> Validate checkbox on the client with FluentValidation/MVC 3

Here it is:

First, I updated the javascript function with the following.

$.validator.addMethod('equaltovalue', function (value, element, params) {
    if ($(element).is(':checkbox')) {
        value = $(element).is(':checked') ? "true" : "false";
    }
    return params.valuetocompare.toLowerCase() === value.toLowerCase();
});

Secondly, I updated EqualToValueFluentValidationPropertyValidator with the following:

public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
    EqualValidator EqualValidator 
    {
        get { return (EqualValidator)Validator; }
    }

    public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) : base(metadata, controllerContext, rule, validator) {
        ShouldValidate = false;
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
        if (!ShouldGenerateClientSideRules()) yield break;

        var propertyToCompare = EqualValidator.MemberToCompare as PropertyInfo;
        if(propertyToCompare != null) {
            // If propertyToCompare is not null then we're comparing to another property.
            // If propertyToCompare is null then we're either comparing against a literal value, a field or a method call.
            // We only care about property comparisons in this case.

            var comparisonDisplayName =
                ValidatorOptions.DisplayNameResolver(Rule.TypeToValidate, propertyToCompare, null)
                ?? propertyToCompare.Name.SplitPascalCase();

            var formatter = new MessageFormatter()
                .AppendPropertyName(Rule.GetDisplayName())
                .AppendArgument("ComparisonValue", comparisonDisplayName);


            string message = formatter.BuildMessage(EqualValidator.ErrorMessageSource.GetString());
            yield return new ModelClientValidationEqualToRule(message, CompareAttribute.FormatPropertyForClientValidation(propertyToCompare.Name)) ;
        }
        else
        {
            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;
        }
    }
}

For FluentValidation v8

public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
    EqualValidator EqualValidator
    {
        get { return (EqualValidator)Validator; }
    }

    public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
        : base(metadata, controllerContext, rule, validator)
    {
        ShouldValidate = false;
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        if (!ShouldGenerateClientSideRules())
            yield break;

        var propertyToCompare = EqualValidator.MemberToCompare as PropertyInfo;
        if (propertyToCompare != null)
        {
            // If propertyToCompare is not null then we're comparing to another property.
            // If propertyToCompare is null then we're either comparing against a literal value, a field or a method call.
            // We only care about property comparisons in this case.

            var comparisonDisplayName =
                ValidatorOptions.DisplayNameResolver(Rule.TypeToValidate, propertyToCompare, null)
                ?? propertyToCompare.Name.SplitPascalCase();

            var formatter = new MessageFormatter()
                .AppendPropertyName(Rule.GetDisplayName())
                .AppendArgument("ComparisonValue", comparisonDisplayName);


            string message;
            try
            {
                message = EqualValidator.Options.ErrorMessageSource.GetString(null);

            }
            catch (FluentValidationMessageFormatException)
            {
                // User provided a message that contains placeholders based on object properties. We can't use that here, so just fall back to the default. 
                message = ValidatorOptions.LanguageManager.GetStringForValidator<EqualValidator>();
            }
            message = formatter.BuildMessage(message);

#pragma warning disable 618
            yield return new ModelClientValidationEqualToRule(message, CompareAttribute.FormatPropertyForClientValidation(propertyToCompare.Name));
#pragma warning restore 618
        }
        else
        {
            var errorMessage = new MessageFormatter()
                .AppendPropertyName(Rule.GetDisplayName())
                .AppendArgument("ValueToCompare", EqualValidator.ValueToCompare)
                .BuildMessage(EqualValidator.Options.ErrorMessageSource.GetString(null));

            var rule = new ModelClientValidationRule
            {
                ErrorMessage = errorMessage,
                ValidationType = "equaltovalue"
            };
            rule.ValidationParameters["valuetocompare"] = EqualValidator.ValueToCompare;
            yield return rule;
        }
    }
}


来源:https://stackoverflow.com/questions/21345078/fluentvalidation-validate-checkbox-and-password-on-the-client-with-equalvalidato

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!