在ASP.Net MVC 5中,可以通过继承DataAnnotationsModelValidator并使用DataAnnotationsModelValidatorProvider.RegisterAdapter(...)进行注册来实现自定义数据注释验证器。在ASP.Net Core MVC中,我该如何实现这一目标?
我在ASP.net core MVC 6 Data Annotations separation of concerns发现了类似的问题,但有人能告诉我简单的示例代码吗?
在我看来,ASP.NET Core MVC不再支持DataAnnotationsModelValidatorProvider.RegisterAdapter
了。我发现的解决方案如下:
假设我想将RequiredAttribute
的Validator更改为我自己的验证器适配器(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;
}
}
2-添加CustomValidationAttribute Adapter Provider以启动:
将以下行添加到Startup.cs中的public void ConfigureServices(IServiceCollection services)
:
services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider> ();
这是我的RequiredAttribute适配器适配器:
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());
}
}
参考文献:
1-请参阅Microsoft的示例:Entropy项目:这是针对.NET Core的不同功能的一个很好的示例。在这个问题中:请参阅Mvc.LocalizationSample.Web示例中的MinLengthSixAttribute
实现:
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
要通过注释定义自定义验证器,您可以定义自己的类,该类派生自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.");
}
}
}
第二种方法是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"});
}
}
您可以在https://docs.asp.net/en/latest/mvc/models/validation.html#custom-validation中找到有关自定义验证的更多信息。