<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Abp vNext異常處理的缺陷/改造方案

          共 11796字,需瀏覽 24分鐘

           ·

          2020-12-26 00:06

          之前吐槽Abp的用戶/租戶管理模塊!今天我又來了,這次我給Abp官方repo提了一個issue。

          目前Website使用Abp vNext開發(fā),免不了要全局處理異常、提示服務器異常信息。

          1. Abp官方異常處理

          Abp項目默認會啟動內置的異常處理,默認不將異常信息發(fā)送到客戶端。
          在AppModule文件ConfigureServices方法中使用以下代碼:

          Configure(options?=>
          {
          ????options.SendExceptionsDetailsToClients?=?true;
          });

          可將異常信息發(fā)送到客戶端:如下圖:

          {
          "error":?{
          "code":?null,
          "message":?"ERROR?[42000]?[Cloudera][ImpalaODBC]?(360)?Syntax?error?occurred?during?query?execution:?[HY000]?:?AnalysisException:?Could?not?resolve?column/field?reference:?'ug_fed89221846a42dc8427932b2965a020'\n",
          "details":?"OdbcException:?ERROR?[42000]?[Cloudera][ImpalaODBC]?(360)?Syntax?error?occurred?during?query?execution:?[HY000]?:?AnalysisException:?Could?not?resolve?column/field?reference:?'ug_fed89221846a42dc8427932b2965a020'\n\nSTACK?TRACE:?at?Gridsum.EAP.Olap.ExecuteQueryLayer.HandleQueryAsync(QueryContext?queryContext,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/Olap/ExecuteQueryLayer.cs:line?81\n?at?Gridsum.EAP.Olap.DistributedCacheLayer.HandleQueryAsync(QueryContext?queryContext,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/Olap/DistributedCacheLayer.cs:line?50\n?at?Gridsum.EAP.DataQuery.AbstractQueryExecutor`1.ExecuteQueryAsync(TQuery?query,?DistributedCacheEntryOptions?options,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/AbstractQueryExecutor.cs:line?60\n?at?Gridsum.EAP.DataQuery.AbstractQueryExecutor`1.ExecuteQueryAsync(TQuery?query,?CancellationToken?token)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/AbstractQueryExecutor.cs:line?47\n?at?Gridsum.EAP.Application.UserGroupService.ClearUserGroupUserAsync(UserGroupUpdateUserDto?updateDto,?String?idshort,?CancellationToken?cancelToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.Application/UserGroup/UserGroupService.cs:line?332\n?at?Gridsum.EAP.Application.UserGroupService.UpdateUserGroupUserAsync(UserGroupUpdateUserDto?updateDto,?CancellationToken?cancelToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.Application/UserGroup/UserGroupService.cs:line?370\n?at?Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation?invocation,?IInvocationProceedInfo?proceedInfo?"42000]?[Cloudera][ImpalaODBC]?(360?"42000]?[Cloudera][ImpalaODBC]?(360)?Syntax?error?occurred?during?query?execution:?[HY000]?:?AnalysisException:?Could?not?resolve?column/field?reference:?'ug_fed89221846a42dc8427932b2965a020'\n\nSTACK?TRACE:?at?Gridsum.EAP.Olap.ExecuteQueryLayer.HandleQueryAsync(QueryContext?queryContext,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/Olap/ExecuteQueryLayer.cs:line?81\n?at?Gridsum.EAP.Olap.DistributedCacheLayer.HandleQueryAsync(QueryContext?queryContext,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/Olap/DistributedCacheLayer.cs:line?50\n?at?Gridsum.EAP.DataQuery.AbstractQueryExecutor`1.ExecuteQueryAsync(TQuery?query,?DistributedCacheEntryOptions?options,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/AbstractQueryExecutor.cs:line?60\n?at?Gridsum.EAP.DataQuery.AbstractQueryExecutor`1.ExecuteQueryAsync(TQuery?query,?CancellationToken?token)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/AbstractQueryExecutor.cs:line?47\n?at?Gridsum.EAP.Application.UserGroupService.ClearUserGroupUserAsync(UserGroupUpdateUserDto?updateDto,?String?idshort,?CancellationToken?cancelToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.Application/UserGroup/UserGroupService.cs:line?332\n?at?Gridsum.EAP.Application.UserGroupService.UpdateUserGroupUserAsync(UserGroupUpdateUserDto?updateDto,?CancellationToken?cancelToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.Application/UserGroup/UserGroupService.cs:line?370\n?at?Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult")?Syntax?error?occurred?during?query?execution:?[HY000]?:?AnalysisException:?Could?not?resolve?column/field?reference:?'ug_fed89221846a42dc8427932b2965a020'\n\nSTACK?TRACE:?at?Gridsum.EAP.Olap.ExecuteQueryLayer.HandleQueryAsync(QueryContext?queryContext,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/Olap/ExecuteQueryLayer.cs:line?81\n?at?Gridsum.EAP.Olap.DistributedCacheLayer.HandleQueryAsync(QueryContext?queryContext,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/Olap/DistributedCacheLayer.cs:line?50\n?at?Gridsum.EAP.DataQuery.AbstractQueryExecutor`1.ExecuteQueryAsync(TQuery?query,?DistributedCacheEntryOptions?options,?CancellationToken?cancellationToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/AbstractQueryExecutor.cs:line?60\n?at?Gridsum.EAP.DataQuery.AbstractQueryExecutor`1.ExecuteQueryAsync(TQuery?query,?CancellationToken?token)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.DataQuery/AbstractQueryExecutor.cs:line?47\n?at?Gridsum.EAP.Application.UserGroupService.ClearUserGroupUserAsync(UserGroupUpdateUserDto?updateDto,?String?idshort,?CancellationToken?cancelToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.Application/UserGroup/UserGroupService.cs:line?332\n?at?Gridsum.EAP.Application.UserGroupService.UpdateUserGroupUserAsync(UserGroupUpdateUserDto?updateDto,?CancellationToken?cancelToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.Application/UserGroup/UserGroupService.cs:line?370\n?at?Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult")\n?at?Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()\n?at?Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation?invocation)\n?at?Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation?invocation,?IInvocationProceedInfo?proceedInfo,?Func`3?proceed?"TResult")\n?at?Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation?invocation,?IInvocationProceedInfo?proceedInfo?"TResult")\n?at?Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()\n?at?Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation?invocation)\n?at?Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation?invocation,?IInvocationProceedInfo?proceedInfo,?Func`3?proceed?"TResult")\n?at?Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation?invocation,?IInvocationProceedInfo?proceedInfo?"TResult")\n?at?Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()\n?at?Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation?invocation)\n?at?Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation?invocation,?IInvocationProceedInfo?proceedInfo,?Func`3?proceed?"TResult")\n?at?Gridsum.EAP.Controllers.UserGroupController.UpdateUserGroupUserAsync(String?id,?CancellationToken?cancelToken)?in?/home/gitlab-runner/builds/ttRjAPVA/0/eap/website/app/src/Gridsum.EAP.HttpApi/Controllers/UserGroupController.cs:line?320\n?at?lambda_method3440(Closure?,?Object?)\n?at?Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper?mapper,?ObjectMethodExecutor?executor,?Object?controller,?Object[]?arguments)\n?at?Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker?invoker,?ValueTask`1?actionResultValueTask)\n?at?Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker?invoker,?Task?lastTask,?State?next,?Scope?scope,?Object?state,?Boolean?isCompleted)\n?at?Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed?context)\n?at?Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State&?next,?Scope&?scope,?Object&?state,?Boolean&?isCompleted)\n?at?Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker?invoker,?Task?lastTask,?State?next,?Scope?scope,?Object?state,?Boolean?isCompleted)\n?at?Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|25_0(ResourceInvoker?invoker,?Task?lastTask,?State?next,?Scope?scope,?Object?state,?Boolean?isCompleted)\n",
          "data":?null,
          "validationErrors":?null
          }
          }

          經過幾天倒騰,發(fā)現(xiàn)Abp vNext的異常處理有幾個問題。

          2.Abp異常處理存在的缺陷

          1. 并沒有如官方所述:自動處理所有異常,實際需要滿足官方所說的某個條件:

          這就導致當Controller Action方法返回的不是object result時,則根本捕獲不到異常(我們暫時不說middleware產生的異常),這應該算Abp的一個Bug

          1. 輸出的異常沒有TraceId, 不利于日志排查
          2. 發(fā)送到客戶端的日志字段message,detail過于詳細冗長,不適合前端顯示

          也可以配置SendExceptionsDetailsToClients,不將異常信息發(fā)送到客戶端,但這樣就因噎廢食了。

          3. 異常處理的目標

          雖然Abp的異常處理有缺陷, 但只是異常信息應用上的缺陷,
          Abp異常處理①對異常的劃分、②異常信息的本地化、③出現(xiàn)異常時寫日志 ?支持的還是相當好。

          基于Abp的異常處理現(xiàn)狀,考慮做一些改進:

          1. 對所有Controller-Action方法捕獲異常, [修復Abp Bug]
          2. 在Abp的異常處理結果中添加 TraceId
          3. 希望將服務端異常分類,簡化后給到前端;同時也不妨礙開發(fā)者查看詳細異常信息。

          4. 揪出Abp異常處理缺陷的根源

          Abp異常處理的核心對象AbpExceptionFilter,實現(xiàn)IAsyncExceptionFilter過濾器, ITransientDependency瞬時注入接口。

          這是一個ServiceFilterAttribute, 你可以理解有個特性作用在每一個Controller的Action方法上

          [ServiceFilter(typeof(AbpExceptionFilter))]

          一旦某個Controller的Action方法發(fā)生異常, 會執(zhí)行如下代碼:

          public?async?Task?OnExceptionAsync(ExceptionContext?context)
          {
          ???if?(!ShouldHandleException(context))
          ???{
          ????????return;
          ???}
          ???await?HandleAndWrapException(context);
          }
          1. ShouldHandleException(context) :監(jiān)測是否應該處理異常,據查該函數(shù)確實存在我上文說的問題:并不能捕獲所有的Action方法的異常。
          2. HandleAndWrapException(context):異常處理步驟:
            • 根據Abp內置的異常類型,自動確定狀態(tài)碼 (這個在Abp官方文檔有講)
            • 序列化異常對象,并向客戶端輸出如下格式:
          {
          "error":?{
          "code":?null,
          "message":?"ERROR?[42000]?[Cloudera][ImpalaODBC]?(360)?Syntax?error?occurred?during?query?execution:?[HY000]?:?AnalysisException:?Could?not?resolve?column/field?reference:?'ug_fed89221846a42dc8427932b2965a020'\n",
          "details":xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx......,
          "data":?null,
          "validationErrors":?null
          }
          }

          ① 輸出的信息,從一開始就沒有包含TraceId;
          ② Abp標準格式化后的異常信息,過于冗長,message,details字段均不適合前端顯示。

          • 寫日志,默認異常級別為Error

          掌握以上源碼,我們可以針對性的改造Abp的核心異常處理類AbpExceptionFilter。

          5. Abp異常處理: 缺陷修復方案

          光說不練假把式

          Abp的AbpExceptionFilter不是抽象類,沒法重載,為達到我們設定的3個目標。
          考慮使用針對性的ExceptionFilter替換默認有缺陷的AbpExceptionFilter。

          ①.? 新建EapExceptionFilter,內容拷貝自AbpExceptionFilter, 并做出如下針對性修改:

          ②. 在AppModule中,替換默認的AbpExceptionFilter為新的EapExceptionFilter過濾器:

          context.Services.AddMvc(options?=>
          {
          ????options.Filters.ReplaceOne(x=>?(x?as?ServiceFilterAttribute)?.ServiceType?.Name==nameof(AbpExceptionFilter),?new?ServiceFilterAttribute(typeof(EapExceptionFilter)));??
          })

          改造的效果如下:

          That's? All

          如果大家真切使用了Abp vNext最新版,

          相信我在第2點提到的Abp異常處理的缺陷,Abp使用者會感同身受;

          第3點提出的幾個目標也是企業(yè)級異常處理要解決的痛點。

          此異常處理的思路也可推及到其他非Abp項目.

          改造方案在Abp官方github issue上:? https://github.com/abpframework/abp/issues/6761

          一家之言,如有其他看法,請不吝賜教!

          (btw,公眾號文章發(fā)布之后,限制修改;若有后續(xù),請 [閱讀原文]!)

          Reference

          1. https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs
          2. https://docs.abp.io/zh-Hans/abp/latest/Exception-Handling
          3. https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0

            閱讀更多




          關注并星標我們
          更多干貨及最佳實踐分享

          瀏覽 31
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天色天天色天天色 | 在线成人黄片 | 国产九色视频 | 国产精品无码专区AV在线播放 | 人人操人人操人摸 |