微软在ASP.NET Core框架中内置了一些验证参数的特性,让我们可以通过这些特性对API请求中的参数进行验证,常用的特性一般有:

  • [ValidateNever] ValidateNeverAttribute 指示应从验证中排除属性或参数。
  • [CreditCard]:验证属性是否具有信用卡格式。
  • [Compare]:验证模型中的两个属性是否匹配。
  • [EmailAddress]:验证属性是否具有电子邮件格式。
  • [Phone]:验证属性是否具有电话号码格式。
  • [Range]:验证属性值是否位于指定范围内。
  • [RegularExpression]:验证 属性值是否与指定的正则表达式匹配。
  • [Required]:验证字段是否不为 null。
  • [StringLength]:验证字符串属性值是否不超过指定的长度限制。
  • [Url]:验证属性是否具有 URL 格式。

  但除了上面这些,还缺少一些我们平时在项目中会经常碰到的验证,例如:需要是纯汉字的姓名、必须包含大小写字母和数字的强密码、QQ号、IPV4或者IPV6地址,以及中国的手机号码和身份证号码等等。

  当我们碰到这些参数需要验证的时候,我们需要如何实现自定义的验证特性呢?此时微软已经指出,让我们去继承ValidationAttribute类,并重写IsValid()即可。

 1 /// <summary>
 2 /// 是否是英文字母、数字组合
 3 /// </summary>
 4 public class EnglishNumberCombinationAttribute : ValidationAttribute
 5 {
 6     /// <summary>
 7     /// 默认的错误提示信息
 8     /// </summary>
 9     private const string error = "无效的英文字母加数字组合";
10 
11     protected override ValidationResult IsValid(object value, ValidationContext validationContext)
12     {
13         //这里是验证的参数的逻辑 value是需要验证的值  而validationContext中包含了验证相关的上下文信息 这里我是有一个自己封装的验证格式的FormatValidation类
14         if (FormatValidation.IsCombinationOfEnglishNumber(value as string))
15             //验证成功返回 success
16             return ValidationResult.Success;
17         //不成功 提示验证错误的信息
18         else return new ValidationResult(ErrorMessage ?? error);
19     }
20 }

  这里是实现一个英文字母数字组合的验证特性,这样我们就可以把它附在在我们请求的参数上,可以是DTO里的属性,也可以是Action上的形参。

 1     public class CreateDTO
 2     {
 3         [Required]
 4         public string StoreName { get; init; }
 5         [Required]
 6         [EnglishNumberCombination(ErrorMessage = "UserId必须是英文字母加数字的组合")]
 7         public string UserId { get; init; }
 8     }
 9 
10   ...
11
12   [HttpGet]
13   public async ValueTask<ActionResult> Delete([EnglishNumberCombination]string UserId, string StoreName)

  Postman测试结果:

ASP.NET Core通过特性实现参数验证

   至于验证的过程,我看了下源码,具体的过程是当我们在startup中services.AddControllers()或者services.AddMvc()的时候,有一个默认的MvcOptions(这个我们是可以配置的),其中有一个ModelValidatorProviders属性,看名字就知道模型验证提供器。ASP.NET Core实现了默认的提供器:

options.ModelValidatorProviders.Add(new DataAnnotationsModelValidatorProvider(
                _validationAttributeAdapterProvider,
                _dataAnnotationLocalizationOptions,
                _stringLocalizerFactory));

  其中_validationAttributeAdapterProvider,是已经依赖注入的IValidationAttributeAdapterProvider,下面是微软实现的代码,感兴趣的小伙伴可以去看一下,可以学到很多设计模式的运用:

 1 namespace Microsoft.AspNetCore.Mvc.DataAnnotations
 2 {
 3     /// <summary>
 4     /// Creates an <see cref="IAttributeAdapter"/> for the given attribute.
 5     /// </summary>
 6     public class ValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
 7     {
 8         /// <summary>
 9         /// Creates an <see cref="IAttributeAdapter"/> for the given attribute.
10         /// </summary>
11         /// <param name="attribute">The attribute to create an adapter for.</param>
12         /// <param name="stringLocalizer">The localizer to provide to the adapter.</param>
13         /// <returns>An <see cref="IAttributeAdapter"/> for the given attribute.</returns>
14         public IAttributeAdapter? GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer? stringLocalizer)
15         {
16             if (attribute == null)
17             {
18                 throw new ArgumentNullException(nameof(attribute));
19             }
20 
21             var type = attribute.GetType();
22 
23             if (typeof(RegularExpressionAttribute).IsAssignableFrom(type))
24             {
25                 return new RegularExpressionAttributeAdapter((RegularExpressionAttribute)attribute, stringLocalizer);
26             }
27             else if (typeof(MaxLengthAttribute).IsAssignableFrom(type))
28             {
29                 return new MaxLengthAttributeAdapter((MaxLengthAttribute)attribute, stringLocalizer);
30             }
31             else if (typeof(RequiredAttribute).IsAssignableFrom(type))
32             {
33                 return new RequiredAttributeAdapter((RequiredAttribute)attribute, stringLocalizer);
34             }
35             else if (typeof(CompareAttribute).IsAssignableFrom(type))
36             {
37                 return new CompareAttributeAdapter((CompareAttribute)attribute, stringLocalizer);
38             }
39             else if (typeof(MinLengthAttribute).IsAssignableFrom(type))
40             {
41                 return new MinLengthAttributeAdapter((MinLengthAttribute)attribute, stringLocalizer);
42             }
43             else if (typeof(CreditCardAttribute).IsAssignableFrom(type))
44             {
45                 return new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-creditcard", stringLocalizer);
46             }
47             else if (typeof(StringLengthAttribute).IsAssignableFrom(type))
48             {
49                 return new StringLengthAttributeAdapter((StringLengthAttribute)attribute, stringLocalizer);
50             }
51             else if (typeof(RangeAttribute).IsAssignableFrom(type))
52             {
53                 return new RangeAttributeAdapter((RangeAttribute)attribute, stringLocalizer);
54             }
55             else if (typeof(EmailAddressAttribute).IsAssignableFrom(type))
56             {
57                 return new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-email", stringLocalizer);
58             }
59             else if (typeof(PhoneAttribute).IsAssignableFrom(type))
60             {
61                 return new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-phone", stringLocalizer);
62             }
63             else if (typeof(UrlAttribute).IsAssignableFrom(type))
64             {
65                 return new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-url", stringLocalizer);
66             }
67             else if (typeof(FileExtensionsAttribute).IsAssignableFrom(type))
68             {
69                 return new FileExtensionsAttributeAdapter((FileExtensionsAttribute)attribute, stringLocalizer);
70             }
71             else
72             {
73                 return null;
74             }
75         }
76     };
77 }
源码

相关文章:

  • 2022-01-31
  • 2021-05-19
  • 2022-01-07
  • 2022-12-23
  • 2021-08-02
  • 2021-12-24
  • 2019-01-16
猜你喜欢
  • 2021-02-02
  • 2021-08-29
  • 2022-12-23
  • 2021-09-24
  • 2022-02-16
  • 2018-03-29
  • 2022-12-23
相关资源
相似解决方案