ASP.Net Core MVC - 自定义属性的客户端验证

问题描述:

在以前版本的 MVC 框架中,自定义验证将通过实现 IClientValidatableGetClientValidationRules 方法来实现.

In previous versions of the MVC framework custom validation would be achieved through implementing IClientValidatable and the GetClientValidationRules method.

但是在 ASP.Net Core MVC 我们这样做没有这个接口,虽然我们有IClientModelValidator,它定义了一个非常相似的方法.然而,它的实现永远不会被调用.

However in ASP.Net Core MVC we do not have this interface, although we do have IClientModelValidator which a defining a very similar method. The implementation of which never gets called however.

那么 - 我们如何为 ASP.NET Core MVC 中的自定义属性实现客户端验证?

So - how do we implement client-side validation for a custom attribute in ASP.NET Core MVC?

IClientModelValidator 实际上是正确的接口.我在下面做了一个人为的示例实现.

The IClientModelValidator is in fact the right interface. I've made a contrived sample implementation below.

注意:重大更改 RC1 和RC2.下面介绍了这两个选项 - 两个版本之间的其余代码相同.

Note: There was a breaking change to the IClientModelValidator interface between RC1 and RC2. Both options are presented below - the rest of the code is the same between both versions.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public sealed class CannotBeRedAttribute : ValidationAttribute, IClientModelValidator
{
    public override bool IsValid(object value)
    {
        var message = value as string;
        return message?.ToUpper() == "RED";
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        MergeAttribute(context.Attributes, "data-val", "true");
        var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
        MergeAttribute(context.Attributes, "data-val-cannotbered", errorMessage);
    }

    private bool MergeAttribute(
        IDictionary<string, string> attributes,
        string key,
        string value)
    {
        if (attributes.ContainsKey(key))
        {
            return false;
        }
        attributes.Add(key, value);
        return true;
    }
}

属性 (RC1)

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public sealed class CannotBeRedAttribute : ValidationAttribute, IClientModelValidator
{
    public override bool IsValid(object value)
    {
        var message = value as string;
        return message?.ToUpper() == "RED";
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
        ClientModelValidationContext context)
    {
        yield return new ModelClientValidationRule(
            "cannotbered",
            FormatErrorMessage(ErrorMessage));
    }
}

型号

public class ContactModel
{
    [CannotBeRed(ErrorMessage = "Red is not allowed!")]
    public string Message { get; set; }
}

查看

@model WebApplication22.Models.ContactModel

<form asp-action="Contact" method="post">
    <label asp-for="Message"></label>
    <input asp-for="Message" />
    <span asp-validation-for="Message"></span>
    <input type="submit" value="Save" />
</form>

@section scripts {
    <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
    <script>
        $.validator.addMethod("cannotbered",
            function (value, element, parameters) {
                return value.toUpperCase() !== "RED";
            });

        $.validator.unobtrusive.adapters.add("cannotbered", [], function (options) {
            options.rules.cannotbered = {};
            options.messages["cannotbered"] = options.message;
        });
    </script>
}