ASP.Net Core MVC中的DataAnnotationsModelValidatorProvider.RegisterAdapter

5 asp.net-core-mvc asp.net-core asp.net-core-1.0

在ASP.Net MVC 5中,可以通过继承DataAnnotationsModelValidator 并使用DataAnnotationsModelValidatorProvider.RegisterAdapter(...)进行注册来实现自定义数据注释验证器.在ASP.Net Core MVC中,我该如何实现这一目标?

我在ASP.net核心MVC 6 Data Annotations中发现了类似的问题,但有人能给我看一些简单的示例代码吗?

Ami*_*mir 9

在我看来,ASP.NET Core MVC不再支持 DataAnnotationsModelValidatorProvider.RegisterAdapter了.我发现的解决方案如下:

假设我想将Validator更改为RequiredAttribute我自己的验证器适配器(MyRequiredAttributeAdaptor),更改默认错误消息EmailAddressAttribute,并将'CompareAttribute'的本地化错误消息源更改为我自己的消息.

1-创建自定义ValidationAttributeAdapterProvider

using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
using Microsoft.Extensions.Localization;
using System.ComponentModel.DataAnnotations;

public class CustomValidationAttributeAdapterProvider
    : ValidationAttributeAdapterProvider, IValidationAttributeAdapterProvider
{
    public CustomValidationAttributeAdapterProvider() { }

    IAttributeAdapter IValidationAttributeAdapterProvider.GetAttributeAdapter(
        ValidationAttribute attribute,
        IStringLocalizer stringLocalizer)
    {
        IAttributeAdapter adapter;
        if (attribute is RequiredAttribute)
        {
            adapter = new MyRequiredAttributeAdaptor((RequiredAttribute) attribute, stringLocalizer);
        }
        else if (attribute is EmailAddressAttribute)
        {
            attribute.ErrorMessage = "Invalid Email Address.";
            adapter = base.GetAttributeAdapter(attribute, stringLocalizer);
        }
        else if (attribute is CompareAttribute)
        {
            attribute.ErrorMessageResourceName = "InvalidCompare"; 
            attribute.ErrorMessageResourceType = typeof(Resources.ValidationMessages);
            var theNewattribute = attribute as CompareAttribute;
            adapter = new CompareAttributeAdapter(theNewattribute, stringLocalizer);
        }
        else
        {
            adapter = base.GetAttributeAdapter(attribute, stringLocalizer);
        }

        return adapter;
    }
}
Run Code Online (Sandbox Code Playgroud)

2-添加CustomValidationAttributeAdapterProvider以启动:

public void ConfigureServices(IServiceCollection services)在Startup.cs中添加以下行:

services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider> ();
Run Code Online (Sandbox Code Playgroud)

这是MyRequiredAttributeAdaptor适配器:

using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Localization;
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;

public class MyRequiredAttributeAdaptor : AttributeAdapterBase<RequiredAttribute>
{
    public MyRequiredAttributeAdaptor(RequiredAttribute attribute, IStringLocalizer stringLocalizer)
        : base(attribute, stringLocalizer)
    {
    }

    public override void AddValidation(ClientModelValidationContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        MergeAttribute(context.Attributes, "data-val", "true");
        MergeAttribute(context.Attributes, "data-val-required", GetErrorMessage(context));
    }

    /// <inheritdoc />
    public override string GetErrorMessage(ModelValidationContextBase validationContext)
    {
        if (validationContext == null)
        {
            throw new ArgumentNullException(nameof(validationContext));
        }

        return GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName());
    }
}
Run Code Online (Sandbox Code Playgroud)

参考文献:

1-请参阅Microsoft的示例:Entropy项目:这是针对.NET Core的不同功能的一个很好的示例.在这个问题中:请参阅MinLengthSixAttributeMvc.LocalizationSample.Web示例中的实现:

https://github.com/aspnet/Entropy/tree/dev/samples/Mvc.LocalizationSample.Web

2-为了查看属性适配器的工作原理,请参阅github上的asp.Microsoft.AspNetCore.Mvc.DataAnnotations:

https://github.com/aspnet/Mvc/tree/dev/src/Microsoft.AspNetCore.Mvc.DataAnnotations


Ral*_*ing -2

要通过注释定义自定义验证器,您可以定义自己的类,该类派生自该方法ValidationAttribute并重写该IsValid方法。无需显式注册此类。

在此示例中,自定义验证属性用于仅接受奇数作为有效值。

public class MyModel
{
    [OddNumber]
    public int Number { get; set; }
}

public class OddNumberAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        try
        {
            var number = (int) value;
            if (number % 2 == 1)
                return ValidationResult.Success;
            else
                return new ValidationResult("Only odd numbers are valid.");
        }
        catch (Exception)
        {
            return new ValidationResult("Not a number.");
        }            
    }
}
Run Code Online (Sandbox Code Playgroud)

第二种方法是 Model 类实现IValidatableObject. 如果验证需要访问模型类的多个成员,这尤其有用。这是奇数验证器的第二个版本:

public class MyModel : IValidatableObject
{
    public int Number { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Number % 2 == 0)
            yield return new ValidationResult(
                 "Only odd numbers are valid.", 
                 new [] {"Number"});
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在https://docs.asp.net/en/latest/mvc/models/validation.html#custom-validation中找到有关自定义验证的更多信息。

  • 感谢你的回复。但我想同时使用服务器端和客户端验证,以及关注点逻辑的分离,为此,我创建了 - `public class requiredIfValidationAttribute : ValidationAttribute { // ... }` 和 `public class requiredIfValidationAdaptor : AttributeAdapterBase&lt;RequiredIfValidationAttribute&gt; { // ...},`但我不知道如何在 **ASP.Net Core MVC** 中注册该适配器。在 MVC 5 中,我使用 **DataAnnotationsModelValidatorProvider.RegisterAdapter(...)**。你还有什么想法吗? (3认同)