DataAnnotationsModelValidatorProvider.RegisterAdapter in ASP.Net Core MVC

五迷三道 提交于 2020-02-20 05:24:05

问题


In ASP.Net MVC 5, custom data annotation validator can be implemented by inheriting DataAnnotationsModelValidator and registering using DataAnnotationsModelValidatorProvider.RegisterAdapter(...). In ASP.Net Core MVC, how can I achieve this?

I found similar question at ASP.net core MVC 6 Data Annotations separation of concerns, but can anyone show me simple example code?


回答1:


It seems to me ASP.NET Core MVC does not have support for DataAnnotationsModelValidatorProvider.RegisterAdapter anymore. The solution I discovered is as follows:

Suppose I want to change the Validator for RequiredAttribute to my own validator adaptor (MyRequiredAttributeAdaptor), Change the default error message of EmailAddressAttribute, and change the Localized Error Message Source for 'CompareAttribute' to my own message.

1- Create a custom 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;
    }
}

2- Add the CustomValidationAttributeAdapterProvider to start up:

Add the following line to public void ConfigureServices(IServiceCollection services) in Startup.cs:

services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider> ();

Here is MyRequiredAttributeAdaptor adaptor:

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());
    }
}

References:

1- See the example of Microsoft: Entropy project: This is a great sample for diffrent features of .NET Core. In this question: see the MinLengthSixAttribute implementation in the Mvc.LocalizationSample.Web sample:

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

2- In order to see how the attribute adapters works see asp.Microsoft.AspNetCore.Mvc.DataAnnotations on github:

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




回答2:


To define a custom validator by a annotation you can define your own class that derives from ValidationAttribute and override the IsValid method. There is no need to register this class explicitly.

In this example a custom validation attribute is used to accept only odd numbers as valid values.

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.");
        }            
    }
}

A second approach is that the Model class implements IValidatableObject. This is especially useful, if validation requires access to multiple members of the model class. Here is the second version of the odd number validator:

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"});
    }
}

You can find more information about custom validation in https://docs.asp.net/en/latest/mvc/models/validation.html#custom-validation.



来源:https://stackoverflow.com/questions/39097786/dataannotationsmodelvalidatorprovider-registeradapter-in-asp-net-core-mvc

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