[AbpvNext源码分析]-9.接口参数的验证

[AbpvNext源码分析]-9.接⼝参数验证
⼀、简要说明
ABP vNext 针对接⼝参数的校验⼯作,分别由过滤器和两步完成。过滤器内部使⽤的 ASP.NET Core MVC 所提供的IModelStateValidator 进⾏处理,⽽使⽤的是 ABP vNext ⾃⼰提供的⼀套 IObjectValidator 进⾏校验⼯作。
关于参数验证相关的代码,分布在以下三个项⽬当中:
Volo.Abp.AspNetCore.Mvc
Volo.Abp.Validation
Volo.Abp.FluentValidation
通过 MVC 的过滤器和 ABP vNext 提供的,我们能够快速地对接⼝的参数、对象的属性进⾏统⼀的验证处理,⽽不会将这些代码扩散到业务层当中。
⽂章信息:
基于的 ABP vNext 版本:1.0.0
创作⽇期:2019 年 10 ⽉ 22 ⽇晚
更新⽇期:暂⽆
⼆、源码分析
2.1 模型验证过滤器
模型验证过滤器是直接使⽤的 MVC 那⼀套模型验证机制,基于数据注解的⽅式进⾏校验。数据注解也就是存放在
System.ComponentModel.DataAnnotations 命名空间下⾯的⼀堆特性定义,例如我们经常在 DTO 上⾯使⽤的 [Required] 、[StringLength]特性等,如果想知道更多的数据注解⽤法,可以前往 进⾏学习。
2.1.1 过滤器的注⼊
模型验证过滤器 (AbpValidationActionFilter) 的定义存放在 Volo.Abp.AspNetCore.Mvc 项⽬内部,它是在模块的 ConfigureService() ⽅法中被注⼊到 IoC 容器的。
AbpAspNetCoreMvcModule ⾥⾯的相关代码:
namespace Volo.Abp.AspNetCore.Mvc
{
[DependsOn(
typeof(AbpAspNetCoreModule),
typeof(AbpLocalizationModule),
typeof(AbpApiVersioningAbstractionsModule),
typeof(AbpAspNetCoreMvcContractsModule),
typeof(AbpUiModule)
)]
public class AbpAspNetCoreMvcModule : AbpModule
{
//
public override void ConfigureServices(ServiceConfigurationContext context)
{
// ...
Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.AddAbp(context.Services);
});
}
// ...
}
}
上述代码是调⽤对 MvcOptions 编写的 AddAbp(this MvcOptions, IServiceCollection) 扩展⽅法,传⼊了我们的 IoC 注册容器(IServiceCollection)。
AbpMvcOptionsExtensions ⾥⾯的相关代码:
internal static class AbpMvcOptionsExtensions
{
public static void AddAbp(this MvcOptions options, IServiceCollection services)
{
AddConventions(options, services);
// 注册过滤器。
AddFilters(options);
AddModelBinders(options);
AddMetadataProviders(options, services);
}
// ...
private static void AddFilters(MvcOptions options)
{
options.Filters.AddService(typeof(AbpAuditActionFilter));
options.Filters.AddService(typeof(AbpFeatureActionFilter));
// 我们的参数验证过滤器。
options.Filters.AddService(typeof(AbpValidationActionFilter));
options.Filters.AddService(typeof(AbpUowActionFilter));
options.Filters.AddService(typeof(AbpExceptionFilter));
}
// ...
}
到这⼀步,我们的 AbpValidationActionFilter 会被添加到 IoC 容器当中,以供 ASP.NET Core Mvc 框架进⾏使⽤。
2.1.2 过滤器的验证流程
我们的验证过滤器通过上述步骤,已经被注⼊到 IoC 容器当中了,以后我们每次的接⼝调⽤都会进⼊ AbpValidationActionFilter 的OnActionExecutionAsync() ⽅法内部。在这个过滤器的内部实现代码中,我们看到 ABP 为我们注⼊了⼀个 IModelStateValidator 对象。
public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency
{
private readonly IModelStateValidator _validator;
public AbpValidationActionFilter(IModelStateValidator validator)
{
_validator = validator;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//TODO: Configuration to disable validation for controllers..?
//TODO: 是否应该增加⼀个配置项,以便开发⼈员禁⽤验证功能?
// 判断当前请求是否是⼀个控制器⾏为,是则返回 true。
/
/ 第⼆个条件会判断当前的接⼝返回值是 IActionResult、JsonResult、ObjectResult、NoContentResult 的⼀种,是则返回 true。
// 这⾥则会忽略不是控制器的⽅法,控制器类型不是上述类型任意⼀种也会被忽略。
if (!context.ActionDescriptor.IsControllerAction() ||
!context.ActionDescriptor.HasObjectResult())
{
await next();
return;
}
// 调⽤验证器进⾏验证操作。
_validator.Validate(context.ModelState);
await next();
}
}
过滤器的⾏为很简单,判断当前的 API 请求是否符合条件,不符合则不进⾏参数验证,否则调⽤ IModelStateValidator 的 Validate ⽅法,将模型状态传递给它进⾏处理。
这个接⼝从名字上看,应该是模型状态验证器。因为我们接⼝上⾯的参数,在 ASP.NET Core MVC 的使⽤当中,会进⾏模型绑定,即建⽴对象到 Http 请求参数的映射。
public interface IModelStateValidator
{
void Validate(ModelStateDictionary modelState);
void AddErrors(IAbpValidationResult validationResult, ModelStateDictionary modelState);
}
ABP vNext 的默认实现是 ModelStateValidator ,它的内部实现也很简单。就是遍历 ModelStateDictio
nary 对象的错误信息,将其添加到⼀个 AbpValidationResult 对象内部的 List 集合。这样做的⽬的,是⽅便后⾯ ABP vNext 进⾏错误抛出。
public class ModelStateValidator : IModelStateValidator, ITransientDependency
{
public virtual void Validate(ModelStateDictionary modelState)
{
var validationResult = new AbpValidationResult();
AddErrors(validationResult, modelState);
if (validationResult.Errors.Any())
{
throw new AbpValidationException(
"ModelState is not valid! See ValidationErrors for details.",
validationResult.Errors
);
}
}
public virtual void AddErrors(IAbpValidationResult validationResult, ModelStateDictionary modelState)
{
if (modelState.IsValid)
{
return;
}
foreach (var state in modelState)
{
foreach (var error in state.Value.Errors)
{
validationResult.Errors.Add(new ValidationResult(error.ErrorMessage, new[] { state.Key }));
}
}
}
}
2.1.3 结果的包装
当过滤器抛出了 AbpValidationException 异常之后,ABP vNext 会在异常过滤器 (AbpExceptionFilter) 内部捕获这个特定异常 (取决于异常继承的 IHasValidationErrors 接⼝),并对其进⾏特殊的包装。
[Serializable]
public class AbpValidationException : AbpException,
IHasLogLevel,
// 注意这个接⼝。
IHasValidationErrors,
IExceptionWithSelfLogging
{
// ...
}

本文发布于:2024-09-22 01:21:34,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/94002.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:验证   过滤器   模型   参数   代码
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议