web-dev-qa-db-ja.com

fluentvalidationおよびasp.net mvc LessThanOrEqualToを使用しない控えめなクライアント検証

次のルールがあります

1つ目は控えめなクライアント側検証を使用して機能しますが、2つ目は機能しません

何かアイデアはありますか?

RuleFor(x => x.StartDate)
    .LessThanOrEqualTo(x => x.EndDate.Value)
    .WithLocalizedMessage(() => CommonRes.Less_Than_Or_Equal_To, filters => CommonRes.Start_Date, filters => CommonRes.End_Date);

RuleFor(x => x.StartDate)
    .GreaterThanOrEqualTo(x => x.AbsoluteStartDate)
    .LessThanOrEqualTo(x => x.AbsoluteEndDate)
    .WithLocalizedMessage(() => CommonRes.Between, filters => CommonRes.Start_Date, filters => filters.AbsoluteStartDate, filters => filters.AbsoluteEndDate);
42
user156888

LessThanOrEqualToルールもGreaterThanOrEqualToルールも、 documentation で説明されているクライアント側検証ではサポートされていません。

つまり、クライアント側の検証を行うには、カスタムFluentValidationPropertyValidatorを記述し、カスタムアダプタを登録してクライアント側を実装できるGetClientValidationRulesメソッドを実装する必要があります。 JavaScriptでの検証ロジック。

Pingを実行する方法に興味がある場合は、例を示します。


更新

リクエストとして、LessThanOrEqualToルールのカスタムクライアント側検証を実装する方法の例を示します。 null不可の日付を使用する特定のケースのみです。可能性のあるすべてのケースについて、このようなカスタムクライアント側の検証ツールを作成することはもちろん可能ですが、かなりの労力が必要になります。

したがって、ビューモデルと対応するバリデーターから始めます。

[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
    [Display(Name = "Start date")]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime StartDate { get; set; }

    public DateTime DateToCompareAgainst { get; set; }
}

public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
    public MyViewModelValidator()
    {
        RuleFor(x => x.StartDate)
            .LessThanOrEqualTo(x => x.DateToCompareAgainst)
            .WithMessage("Invalid start date");
    }
}

次にコントローラー:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            StartDate = DateTime.Now.AddDays(2),
            DateToCompareAgainst = DateTime.Now
        };
        return View(model);
    }

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

およびビュー:

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.Hidden("DateToCompareAgainst", Model.DateToCompareAgainst.ToString("yyyy-MM-dd"))

    @Html.LabelFor(x => x.StartDate)
    @Html.EditorFor(x => x.StartDate)
    @Html.ValidationMessageFor(x => x.StartDate)
    <button type="submit">OK</button>
}

これはすべてこれまでの標準的なものです。動作しますが、クライアントの検証はありません。

最初のステップはFluentValidationPropertyValidatorを書くことです:

public class LessThanOrEqualToFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
    public LessThanOrEqualToFluentValidationPropertyValidator(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 = Validator as LessThanOrEqualValidator;

        var errorMessage = new MessageFormatter()
            .AppendPropertyName(this.Rule.GetDisplayName())
            .BuildMessage(validator.ErrorMessageSource.GetString());

        var rule = new ModelClientValidationRule
        {
            ErrorMessage = errorMessage,
            ValidationType = "lessthanorequaldate"
        };
        rule.ValidationParameters["other"] = CompareAttribute.FormatPropertyForClientValidation(validator.MemberToCompare.Name);
        yield return rule;
    }
}

fluentValidationプロバイダーの構成時にApplication_Startに登録されます。

FluentValidationModelValidatorProvider.Configure(x =>
{
    x.Add(typeof(LessThanOrEqualValidator), (metadata, context, rule, validator) => new LessThanOrEqualToFluentValidationPropertyValidator(metadata, context, rule, validator));
});

最後のビットは、クライアント上のカスタムアダプターです。したがって、控えめなクライアント側の検証を有効にするために、もちろん2つのスクリプトをページに追加します。

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

カスタムアダプター:

(function ($) {
    $.validator.unobtrusive.adapters.add('lessthanorequaldate', ['other'], function (options) {
        var getModelPrefix = function (fieldName) {
            return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
        };

        var appendModelPrefix = function (value, prefix) {
            if (value.indexOf("*.") === 0) {
                value = value.replace("*.", prefix);
            }
            return value;
        }

        var prefix = getModelPrefix(options.element.name),
            other = options.params.other,
            fullOtherName = appendModelPrefix(other, prefix),
            element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

        options.rules['lessthanorequaldate'] = element;
        if (options.message != null) {
            options.messages['lessthanorequaldate'] = options.message;
        }
    });

    $.validator.addMethod('lessthanorequaldate', function (value, element, params) {
        var parseDate = function (date) {
            var m = date.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
            return m ? new Date(parseInt(m[1]), parseInt(m[2]) - 1, parseInt(m[3])) : null;
        };

        var date = parseDate(value);
        var dateToCompareAgainst = parseDate($(params).val());

        if (isNaN(date.getTime()) || isNaN(dateToCompareAgainst.getTime())) {
            return false;
        }

        return date <= dateToCompareAgainst;
    });

})(jQuery);
79
Darin Dimitrov

Darinの例には時代遅れのものがいくつかあるので、ここでは、数値比較を行うより更新された例を示します。ただし、日付比較のために簡単に調整できます。

Javascript:

(function ($)
{
    $.validator.addMethod("lessthanorequal", function(value, element, param)
    {
        return this.optional(element) || parseFloat(value) <= parseFloat(param);
    }, "Must be less than");

    $.validator.unobtrusive.adapters.add("lessthanorequal", ["field"], function (options)
    {
        options.rules["lessthanorequal"] = options.params.field;
        if (options.message) options.messages["lessthanorequal"] = options.message;
    });
})(jQuery);

C#

public class LessThanOrEqualPropertyValidator : FluentValidationPropertyValidator
{

    public LessThanOrEqualPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
        : base(metadata, controllerContext, rule, validator)
    {
    }

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

        var formatter = new MessageFormatter().AppendPropertyName(Rule.PropertyName);
        string message = formatter.BuildMessage(Validator.ErrorMessageSource.GetString());
        var rule = new ModelClientValidationRule
        {
            ValidationType = "lessthanorequal",
            ErrorMessage = message
        };

         rule.ValidationParameters["field"] =  ((LessThanOrEqualValidator)Validator).ValueToCompare;
        yield return rule;
    }
}

Global.asax Application_Start:

FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure(x =>
{
    x.Add(typeof(LessThanOrEqualValidator), (metadata, context, description, validator) => new LessThanOrEqualPropertyValidator(metadata, context, description, validator));
});

そのため、LessThanOrEqualを使用する番号ルールはすべてクライアント側で検証されます。

6
ROFLwTIME

LessThanOrEqualToおよびGreaterThanOrEqualToは、すぐに使用できるクライアント側の検証をサポートしていません。

ただし、InclusiveBetweenはサポートされています。したがって、InclusiveBetweenを使用できます。

RuleFor(x => x.StartDate)
    .InclusiveBetween(x.AbsoluteStartDate, x.AbsoluteEndDate)

サポートされているクライアント側メソッド に関する詳細については、ドキュメントを参照してください。

3
ndequeker