接着上面的一个部分来叙述,这一篇我们来重点看ABP中的AbpUowActionFilter、AbpExceptionFilter、AbpResultFilter这三个部分也是按照之前的思路来一个个介绍,当然这里面如果和前面的Interceptor有重复的部分,那么将会对两者进行一个对比并作出相关的说明,那么我们现在来一步步来分析这几个Filter的细节。

  四   AbpUowActionFilter

  这个我们需要和之前的UnitOfWorkInterceptor中的上篇和下篇来进行对比,工作单元部分是整个ABP中非常重要的一个部分,这里我们也来简要的进行分析,详细的过程可以参考UnitOfWorkInterceptor中的过程来说明,这里主要是说一下两者的不同之处,这里我们先看看这部分的代码,然后再进行分析。

public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency{private readonly IUnitOfWorkManager _unitOfWorkManager;private readonly IAbpAspNetCoreConfiguration _aspnetCoreConfiguration;private readonly IUnitOfWorkDefaultOptions _unitOfWorkDefaultOptions;public AbpUowActionFilter(IUnitOfWorkManager unitOfWorkManager,IAbpAspNetCoreConfiguration aspnetCoreConfiguration,IUnitOfWorkDefaultOptions unitOfWorkDefaultOptions){_unitOfWorkManager = unitOfWorkManager;_aspnetCoreConfiguration = aspnetCoreConfiguration;_unitOfWorkDefaultOptions = unitOfWorkDefaultOptions;}public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){if (!context.ActionDescriptor.IsControllerAction()){await next();return;}var unitOfWorkAttr = _unitOfWorkDefaultOptions.GetUnitOfWorkAttributeOrNull(context.ActionDescriptor.GetMethodInfo()) ??_aspnetCoreConfiguration.DefaultUnitOfWorkAttribute;if (unitOfWorkAttr.IsDisabled){await next();return;}using (var uow = _unitOfWorkManager.Begin(unitOfWorkAttr.CreateOptions())){var result = await next();if (result.Exception == null || result.ExceptionHandled){await uow.CompleteAsync();}}}}

  这里我们来一步步进行分析,首先第一步也是判断当前执行的方法是否是ControllerAction,确确来说就是当前执行的方法是否位于Controller的内部,如果当前方法不是ControllerAction的话那么就不再拦截当前方法,这个和前面分析的是一样的。然后第二部就是通过下面的GetUnitOfWorkAttributeOrNull这个方法来判断能够进行后续操作。

 internal static class UnitOfWorkDefaultOptionsExtensions{public static UnitOfWorkAttribute GetUnitOfWorkAttributeOrNull(this IUnitOfWorkDefaultOptions unitOfWorkDefaultOptions, MethodInfo methodInfo){var attrs = methodInfo.GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();if (attrs.Length > 0){return attrs[0];}attrs = methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();if (attrs.Length > 0){return attrs[0];}if (unitOfWorkDefaultOptions.IsConventionalUowClass(methodInfo.DeclaringType)){return new UnitOfWorkAttribute(); //Default}return null;}public static bool IsConventionalUowClass(this IUnitOfWorkDefaultOptions unitOfWorkDefaultOptions, Type type){return unitOfWorkDefaultOptions.ConventionalUowSelectors.Any(selector => selector(type));}}

  这是一个扩展方法,主要是获取当前方法的名称为UnitOfWork的自定义属性,当然这个【UnitOfWork】可以定义在当前方法的上面,当然也可以定义在该方法的类的上面,如果定义在类的上面则表示整个类都拥有UnitOfWork特性。另外我们可以定义我们自己的规则,从而确保当前方法能够运用到UnitOfWork的特性,具体的方法就是在UnitOfWorkDefaultOptions中定义自己的ConventionalUowSelectors,我们来看看UnitOfWorkDefaultOptions的实现。

internal class UnitOfWorkDefaultOptions : IUnitOfWorkDefaultOptions{public TransactionScopeOption Scope { get; set; }/// <inheritdoc/>public bool IsTransactional { get; set; }/// <inheritdoc/>public TimeSpan? Timeout { get; set; }/// <inheritdoc/>public bool IsTransactionScopeAvailable { get; set; }/// <inheritdoc/>public IsolationLevel? IsolationLevel { get; set; }public IReadOnlyList<DataFilterConfiguration> Filters => _filters;private readonly List<DataFilterConfiguration> _filters;public List<Func<Type, bool>> ConventionalUowSelectors { get; }public UnitOfWorkDefaultOptions(){_filters = new List<DataFilterConfiguration>();IsTransactional = true;Scope = TransactionScopeOption.Required;IsTransactionScopeAvailable = true;ConventionalUowSelectors = new List<Func<Type, bool>>{type => typeof(IRepository).IsAssignableFrom(type) ||typeof(IApplicationService).IsAssignableFrom(type)};}public void RegisterFilter(string filterName, bool isEnabledByDefault){if (_filters.Any(f => f.FilterName == filterName)){throw new AbpException("There is already a filter with name: " + filterName);}_filters.Add(new DataFilterConfiguration(filterName, isEnabledByDefault));}public void OverrideFilter(string filterName, bool isEnabledByDefault){_filters.RemoveAll(f => f.FilterName == filterName);_filters.Add(new DataFilterConfiguration(filterName, isEnabledByDefault));}}

  在这个里面有一个公共的名称为ConventionalUowSelectors的Func委托集合,在这个里面我们默认添加了从IRepository或者IApplicationService的类型自动添加UnitOfWork的特性的方式,当然我们也可以在我们的Module里面添加自己的UowSelector,通过上面的代码我们可以了解整个过程,在获取了当前的方法的UnitOfWorkAttribute后我们需要判断当前的IsDisable是否为true,如果为true那么再次跳过UnitOfWork的过程,最后就是通过UnitOfWorkManager来启动工作单元,其内部具体的执行过程请参考UnitOfWorkInterceptor中详细的过程。

  五   AbpExceptionFilter

  这个应该在ABP中非常常见的一类Filter,在我们的代码中底层抛出异常之后我们到底该怎么处理呢?我们来看看ABP中写了哪些?处理过程又是什么样的?

 public class AbpExceptionFilter : IExceptionFilter, ITransientDependency{public ILogger Logger { get; set; }public IEventBus EventBus { get; set; }private readonly IErrorInfoBuilder _errorInfoBuilder;private readonly IAbpAspNetCoreConfiguration _configuration;public AbpExceptionFilter(IErrorInfoBuilder errorInfoBuilder, IAbpAspNetCoreConfiguration configuration){_errorInfoBuilder = errorInfoBuilder;_configuration = configuration;Logger = NullLogger.Instance;EventBus = NullEventBus.Instance;}public void OnException(ExceptionContext context){if (!context.ActionDescriptor.IsControllerAction()){return;}var wrapResultAttribute =ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(context.ActionDescriptor.GetMethodInfo(),_configuration.DefaultWrapResultAttribute);if (wrapResultAttribute.LogError){LogHelper.LogException(Logger, context.Exception);}if (wrapResultAttribute.WrapOnError){HandleAndWrapException(context);}}private void HandleAndWrapException(ExceptionContext context){if (!ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType)){return;}context.HttpContext.Response.StatusCode = GetStatusCode(context);context.Result = new ObjectResult(new AjaxResponse(_errorInfoBuilder.BuildForException(context.Exception),context.Exception is AbpAuthorizationException));EventBus.Trigger(this, new AbpHandledExceptionData(context.Exception));context.Exception = null; //Handled!}protected virtual int GetStatusCode(ExceptionContext context){if (context.Exception is AbpAuthorizationException){return context.HttpContext.User.Identity.IsAuthenticated? (int)HttpStatusCode.Forbidden: (int)HttpStatusCode.Unauthorized;}if (context.Exception is AbpValidationException){return (int)HttpStatusCode.BadRequest;}if (context.Exception is EntityNotFoundException){return (int)HttpStatusCode.NotFound;}return (int)HttpStatusCode.InternalServerError;}}

  在这个方法中,首先也是过滤ControllerAction,然后就会获取当前执行方法或者其所属的类上面是否定义了WrapResultAttribute,如果找不到自定义的WrapResultAttribute,那么会为其添加一个默认的WrapResultAttribute,默认的WrapResultAttribute中默认定义LogError=true,所以默认会通过LogHelper.LogException(Logger, context.Exception)来记录当前系统中异常信息作为日志文件。当然这里我们也可以看看HandleAndWrapException中到底做了些什么?

  首先是判断当前的方法的返回值是否是一个ObjectResult,那么到底什么是ObjectResult,我们一起来看看。

 public static bool IsObjectResult(Type returnType){//Get the actual return type (unwrap Task)if (returnType == typeof(Task)){returnType = typeof(void);}else if (returnType.GetTypeInfo().IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)){returnType = returnType.GenericTypeArguments[0];}if (typeof(IActionResult).GetTypeInfo().IsAssignableFrom(returnType)){if (typeof(JsonResult).GetTypeInfo().IsAssignableFrom(returnType) || typeof(ObjectResult).GetTypeInfo().IsAssignableFrom(returnType)){return true;}return false;}return true;}

  首先来判断当前方法的返回值是否继承自IActionResult,在满足这个条件以后再来看当前方法的返回值是否继承自JsonResult或者是ObjectResult,如果是那么就返回true。返回true后我们会获取当前Response的状态码并且以AjaxRespone的形式返回。这里我们看看在实际的业务中我们的处理方式,看下面的代码。

 /// <summary>/// API 的未捕捉异常处理/// </summary>public class ApiExceptionFilter : IExceptionFilter {/// <summary>/// 仅针对 /api/ 开头的 HTTP API 处理异常/// </summary>/// <param name="context">异常的上下文</param>public void OnException(ExceptionContext context) {var route = context.ActionDescriptor.AttributeRouteInfo.Template;if (route.StartsWith("api/")) {HandleException(context);}}/// <summary>/// 针对不同的异常,HTTP Response 使用不同的 Status Code, Body 均定义为 { "message": "exception message" }/// </summary>/// <param name="context"></param>private void HandleException(ExceptionContext context) {context.HttpContext.Response.StatusCode = GetStatusCode(context);if (context.Exception is AbpValidationException exception) {context.Result = new ObjectResult(new {// Message = "你的请求无效",ValidationErrors = GetValidationErrorInfos(exception),Message = GetValidationErrorNarrative(exception)});} else if (context.Exception is FileValidationException fileValidationException) {context.Result = new ObjectResult(new {payload = fileValidationException.FileName,fileValidationException.Message});} else {var message = context.Exception.Message;if (context.Exception.InnerException is ValidationException)message = context.Exception.InnerException.Message;context.Result = new ObjectResult(new {Message = message});}context.ExceptionHandled = true;}private int GetStatusCode(ExceptionContext context) {if (context.Exception is AbpAuthorizationException) {return context.HttpContext.User.Identity.IsAuthenticated? StatusCodes.Status403Forbidden: StatusCodes.Status401Unauthorized;}if (context.Exception is AbpValidationException|| context.Exception is UserFriendlyException|| context.Exception is ValidationException|| context.Exception is FileValidationException|| context.Exception.InnerException is ValidationException) {return StatusCodes.Status400BadRequest;}if (context.Exception is EntityNotFoundException) {return StatusCodes.Status404NotFound;}if (context.Exception is PreconditionRequiredException) {return StatusCodes.Status428PreconditionRequired;}if (context.Exception is PreconditionFailedException) {return StatusCodes.Status412PreconditionFailed;}return StatusCodes.Status500InternalServerError;}private ValidationErrorInfo[] GetValidationErrorInfos(AbpValidationException validationException) {var validationErrorInfos = new List<ValidationErrorInfo>();foreach (var validationResult in validationException.ValidationErrors) {var validationError = new ValidationErrorInfo(validationResult.ErrorMessage);if (validationResult.MemberNames != null && validationResult.MemberNames.Any()) {validationError.Members = validationResult.MemberNames.Select(m => m.ToCamelCase()).ToArray();}validationErrorInfos.Add(validationError);}return validationErrorInfos.ToArray();}private string GetValidationErrorNarrative(AbpValidationException validationException) {var detailBuilder = new StringBuilder();detailBuilder.AppendLine("验证过程中检测到以下错误");foreach (var validationResult in validationException.ValidationErrors) {detailBuilder.AppendFormat(" - {0}", validationResult.ErrorMessage);detailBuilder.AppendLine();}return detailBuilder.ToString();}}

  在实际的业务过程中我们会将当前的报错信息已一定的结构返回给调用的前端,让前端去处理具体的异常信息,通常会将错误信息显示在界面上方几秒中,然后退出的方式。

  六   AbpResultFilter

  这个在实际过程中用的不是很多我们也来看看到底会做些什么吧?

 public class AbpResultFilter : IResultFilter, ITransientDependency{private readonly IAbpAspNetCoreConfiguration _configuration;private readonly IAbpActionResultWrapperFactory _actionResultWrapperFactory;public AbpResultFilter(IAbpAspNetCoreConfiguration configuration, IAbpActionResultWrapperFactory actionResultWrapper){_configuration = configuration;_actionResultWrapperFactory = actionResultWrapper;}public virtual void OnResultExecuting(ResultExecutingContext context){if (!context.ActionDescriptor.IsControllerAction()){return;}var methodInfo = context.ActionDescriptor.GetMethodInfo();//var clientCacheAttribute = ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(//    methodInfo,//    _configuration.DefaultClientCacheAttribute//);//clientCacheAttribute?.Apply(context);var wrapResultAttribute =ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(methodInfo,_configuration.DefaultWrapResultAttribute);if (!wrapResultAttribute.WrapOnSuccess){return;}_actionResultWrapperFactory.CreateFor(context).Wrap(context);}public virtual void OnResultExecuted(ResultExecutedContext context){//no action}}

  这个里面最重要就是最后一个Wrap方法,这个方法会根据返回的结果是JsonResult还是ObjectResult来做不同的处理,这里我以ObjectResult为例来进行说明。

 public class AbpObjectActionResultWrapper : IAbpActionResultWrapper{private readonly IServiceProvider _serviceProvider;public AbpObjectActionResultWrapper(IServiceProvider serviceProvider){_serviceProvider = serviceProvider;}public void Wrap(ResultExecutingContext actionResult){var objectResult = actionResult.Result as ObjectResult;if (objectResult == null){throw new ArgumentException($"{nameof(actionResult)} should be ObjectResult!");}if (!(objectResult.Value is AjaxResponseBase)){objectResult.Value = new AjaxResponse(objectResult.Value);if (!objectResult.Formatters.Any(f => f is JsonOutputFormatter)){objectResult.Formatters.Add(new JsonOutputFormatter(_serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value.SerializerSettings,_serviceProvider.GetRequiredService<ArrayPool<char>>()));}}}}

  这里面也比较简单就是将最终的结果以Json的格式进行输出。

  最后,点击这里返回整个ABP系列的主目录。

  

  

转载于:https://www.cnblogs.com/seekdream/p/10490267.html

ABP中的Filter(下)相关推荐

  1. 【转】ABP源码分析三十五:ABP中动态WebAPI原理解析

    动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类就可以对外提供WebAPI的功能, ...

  2. ABP中的数据过滤器

      本文首先介绍了ABP内置的软删除过滤器(ISoftDelete)和多租户过滤器(IMultiTenant),然后介绍了如何实现一个自定义过滤器,最后介绍了在软件开发过程中遇到的实际问题,同时给出了 ...

  3. Java Web中的Filter和Interceptor的区别

    2019独角兽企业重金招聘Python工程师标准>>> 1.问题的来源 项目中使用了Filter,进行白名单的控制,同时使用了Filter进行了跨域请求的控制,使用了Intercep ...

  4. Intel Realsense pyrealsense rs.decimation_filter()类(通过使用具有特定内核大小的中值执行下采样)(抽取过滤器/抽取滤波器)

    from decimation_filter.py class decimation_filter(filter):""" Performs downsampling b ...

  5. web.xml 中的filter

    Servlet API的2.3版本中最重要的一个新功能就是能够为servlet和JSP页面定义过滤器.过滤器提供了某些早期服务器所支持的非标准"servlet链接"的一种功能强大且 ...

  6. 【转】ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数必然已完成了执行 ...

  7. “Abp.AbpException: Unknown filter name: MayHaveTenant. Be sure this filter is registered before.”的解决

    本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:"Abp.AbpException: Unknown filter name: MayHaveTenant. Be sure ...

  8. ABP中使用Redis Cache(1)

    本文将讲解如何在ABP中使用Redis Cache以及使用过程中遇到的各种问题.下面就直接讲解使用步骤,Redis环境的搭建请直接网上搜索. 使用步骤: 一.ABP环境搭建 到http://www.a ...

  9. ABP架构学习系列二:ABP中配置的注册和初始化

    一.手工搭建平台 1.创建项目 创建MVC5项目,手动引入Abp.Abp.Web.Abp.Web.Mvc.Abp.Web.Api 使用nuget添加Newtonsoft.Json.Castle.Cor ...

最新文章

  1. Mysql aborted_client_MySQL之aborted connections和aborted clients
  2. ZOJ 1057 Undercut(简单模拟)
  3. Atlas学习之开始篇[转]
  4. 图的最短路算法(Dijkstra和Floyd-Warshall)
  5. 软件项目管理案例教程(第三版)其它课后题答案持续更新,欢迎收藏+关注
  6. 怎么找回计算机用户名密码怎么办,电脑steam账号密码忘记了怎么办|电脑找回steam账户的方法...
  7. java utf8 gbk 乱码,java UTF-8转GBK不乱码
  8. 可靠性测试设备技术含量_可靠性测试中心
  9. ubuntu20磁盘新建分区与挂载
  10. Kali Linux 安装网易云音乐打不开的解决方法
  11. 什么是外包公司?要不要去外包公司?
  12. Amazon ES现更名为Amazon OpenSearch Service并支持OpenSearch 1.0
  13. Mybatis001_JDBC
  14. [转载] 七龙珠第一部——第111话 龟仙人最后的魔封波
  15. 自制图像标注软件 —— 支持mask-rcnn等算法
  16. 【前端小实战】页面文字搜索功能
  17. 【小程序】自定义导航栏
  18. 爬取豆瓣电影剧情片排行榜
  19. Servlet_Jsp学习笔记:
  20. 2022第二届网刃杯网络安全大赛-Web

热门文章

  1. 为窗口添加滚动条事件
  2. C++基本要点复习--------coursera程序设计实习(PKU)的lecture notes
  3. 在eclipse中通过基于spring data的easyrest风格的maven项目操纵cassandra和lucene
  4. 引起路由器重启的“元凶”
  5. MySQL01-安装mysql数据库
  6. 区块链学习之-发布合约
  7. 什么是棉绒,它如何节省您的时间?
  8. [HTTP协议]基础篇-待完结
  9. Python培训分享:python如何用cookie实现自动模拟登录?
  10. APP测试和传统软件测试有什么区别