MvcFilter
在Volo.Abp.AspNetCore.Mvc 👉 Validation文件夹中
namespace Volo.Abp.AspNetCore.Mvc.Validation;
public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// 是否是控制器行为
// 是否是JsonResult、ObjectResult、NoContentResultd的一种
// 不是则跳过
if (!context.ActionDescriptor.IsControllerAction() ||
!context.ActionDescriptor.HasObjectResult())
{
await next();
return;
}
// 是否开启验证
if (!context.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>().Value.AutoModelValidation)
{
await next();
return;
}
// 该方法是否禁用验证
if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(context.ActionDescriptor.GetMethodInfo()) != null)
{
await next();
return;
}
// 该控制器是否禁用验证
if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(context.Controller.GetType()) != null)
{
await next();
return;
}
// https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.memberinfo.declaringtype
// 该方法的声明是不是上下文中控制器的
if (context.ActionDescriptor.GetMethodInfo().DeclaringType != context.Controller.GetType())
{
var baseMethod = context.ActionDescriptor.GetMethodInfo();
// 获取重写前的方法
var overrideMethod = context.Controller.GetType().GetMethods().FirstOrDefault(x =>
x.DeclaringType == context.Controller.GetType() &&
x.Name == baseMethod.Name &&
x.ReturnType == baseMethod.ReturnType &&
x.GetParameters().Select(p => p.ToString()).SequenceEqual(baseMethod.GetParameters().Select(p => p.ToString())));
if (overrideMethod != null)
{
// 该方法是否禁用验证
if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(overrideMethod) != null)
{
await next();
return;
}
}
}
// 调用IModelStateValidator模型状态验证器进行验证
context.GetRequiredService<IModelStateValidator>().Validate(context.ModelState);
await next();
}
}
IModelStateValidator
的默认实现ModelStateValidator
。实现很简单,就是判断是否通过验证,然后将未通过的验证提示信息,添加到验证结果中,然后用验证异常AbpValidationException
抛出,交给异常处理器处理。
namespace Volo.Abp.AspNetCore.Mvc.Validation;
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 }));
}
}
}
}
通过AbpMvcOptionsExtensions
扩展方法统一将过滤器注入到Mvc过滤器集合中。
internal static class AbpMvcOptionsExtensions
{
public static void AddAbp(this MvcOptions options, IServiceCollection services)
{
,..
// 注入
AddActionFilters(options);
...
}
private static void AddActionFilters(MvcOptions options)
{
...
// 验证过滤器
options.Filters.AddService(typeof(AbpValidationActionFilter));
...
}
...
}
拦截器
只要实现了IValidationEnabled
接口就将其添加到拦截器中。
public static class ValidationInterceptorRegistrar
{
public static void RegisterIfNeeded(IOnServiceRegistredContext context)
{
if (ShouldIntercept(context.ImplementationType))
{
context.Interceptors.TryAdd<ValidationInterceptor>();
}
}
private static bool ShouldIntercept(Type type)
{
return !DynamicProxyIgnoreTypes.Contains(type) && typeof(IValidationEnabled).IsAssignableFrom(type);
}
}
流程 源码地址
- 拦截器组装
MethodInvocationValidationContext
上下文,调用IMethodInvocationValidator.ValidateAsync
进行验证。 - 默认实现
MethodInvocationValidator
,先进行判断- 参数不能为空
- 修饰符必须是
Public
- 未使用
DisableValidationAttribute
特性 - 参数数量和参数值数量相等(一对一)
MethodInvocationValidator
调用IObjectValidator.GetErrorsAsync()
方法获取验证结果- 默认实现
ObjectValidator
调用AbpValidationOptions
选项中的ObjectValidationContributors
属性,该属性提供了IObjectValidationContributor
集合,IObjectValidationContributor
是验证辅助类型。当前类库中提供了DataAnnotationObjectValidationContributor
模型注解验证,就是上面MVC那一套。DataAnnotationObjectValidationContributor
里面使用了递归验证,最大深度为8。
DataAnnotationObjectValidationContributor
调用了DefaultAttributeValidationResultProvider
获取验证结果,默认实现使用了ValidationAttribute.GetValidationResult()
- 在MVC中重新用
AbpMvcAttributeValidationResultProvider
继承并重写了DefaultAttributeValidationResultProvider
的GetOrDefault()
方法。用它实现了本地化。 ```csharp namespace Volo.Abp.AspNetCore.Mvc.Localization;
- 在MVC中重新用
[Dependency(ReplaceServices = true)] public class AbpMvcAttributeValidationResultProvider : DefaultAttributeValidationResultProvider { private readonly AbpMvcDataAnnotationsLocalizationOptions _abpMvcDataAnnotationsLocalizationOptions; private readonly IStringLocalizerFactory _stringLocalizerFactory;
public AbpMvcAttributeValidationResultProvider(
IOptions<AbpMvcDataAnnotationsLocalizationOptions> abpMvcDataAnnotationsLocalizationOptions,
IStringLocalizerFactory stringLocalizerFactory)
{
_abpMvcDataAnnotationsLocalizationOptions = abpMvcDataAnnotationsLocalizationOptions.Value;
_stringLocalizerFactory = stringLocalizerFactory;
}
public override ValidationResult GetOrDefault(ValidationAttribute validationAttribute, object validatingObject, ValidationContext validationContext)
{
var resourceSource = _abpMvcDataAnnotationsLocalizationOptions.AssemblyResources.GetOrDefault(validationContext.ObjectType.Assembly);
if (resourceSource == null)
{
return base.GetOrDefault(validationAttribute, validatingObject, validationContext);
}
if (validationAttribute.ErrorMessage == null)
{
ValidationAttributeHelper.SetDefaultErrorMessage(validationAttribute);
}
if (validationAttribute.ErrorMessage != null)
{
validationAttribute.ErrorMessage = _stringLocalizerFactory.Create(resourceSource)[validationAttribute.ErrorMessage];
}
return base.GetOrDefault(validationAttribute, validatingObject, validationContext);
}
}
<a name="d0tco"></a>
## FluentValidation
引入了第三方类库`FluentValidation`,并实现了`IObjectValidationContributor`。
```csharp
namespace Volo.Abp.FluentValidation;
public class FluentObjectValidationContributor : IObjectValidationContributor, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public FluentObjectValidationContributor(
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
// 通过Ioc获取验证器,然后将验证结果添加到上下文的Errors集合中。
public virtual async Task AddErrorsAsync(ObjectValidationContext context)
{
var serviceType = typeof(IValidator<>).MakeGenericType(context.ValidatingObject.GetType());
var validator = _serviceProvider.GetService(serviceType) as IValidator;
if (validator == null)
{
return;
}
// 获取验证结果
var result = await validator.ValidateAsync((IValidationContext)Activator.CreateInstance(
typeof(ValidationContext<>).MakeGenericType(context.ValidatingObject.GetType()),
context.ValidatingObject));
if (!result.IsValid)
{
// 返回验证失败信息
context.Errors.AddRange(
result.Errors.Select(
error =>
new ValidationResult(error.ErrorMessage, new[] { error.PropertyName })
)
);
}
}
}