DataAnnotationsModelValidatorProvider.RegisterAdapter in ASP.Net Core MVC

In ASP.Net MVC 5, a user data validator can be implemented by inheriting from DataAnnotationsModelValidator and registering with DataAnnotationsModelValidatorProvider.RegisterAdapter (...) . In ASP.Net Core MVC, how can I achieve this?

I found a similar question in ASP.net core MVC 6 Data Annotations problem separation , but can anyone show me a simple code example?

+5
source share
2 answers

It seems to me that ASP.NET Core MVC no longer supports DataAnnotationsModelValidatorProvider.RegisterAdapter . The solution I discovered is this:

Suppose I want to change Validator for RequiredAttribute to my own validator adapter ( MyRequiredAttributeAdaptor ), change the default error message for EmailAddressAttribute and change the source of the localized error messages for "CompareAttribute" to my own message.

1- Creating 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 CustomValidationAttributeAdapterProvider to run:

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

 services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider> (); 

Here is the MyRequiredAttributeAdaptor adapter:

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

Recommendations:

1- See Microsoft Example: Entropy Project: This is a great example for various .NET Core features. 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- To see how attribute adapters work, see asp.Microsoft.AspNetCore.Mvc.DataAnnotations on github:

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

+9
source

To define a custom validator using annotation, you can define your own class derived from ValidationAttribute and override IsValid . There is no need to register this class explicitly.

In this example, the 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."); } } } 

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

 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 at https://docs.asp.net/en/latest/mvc/models/validation.html#custom-validation .

0
source

All Articles