1. 程式人生 > 其它 >【NetCore】新增自定義全域性異常攔截

【NetCore】新增自定義全域性異常攔截

引用

中介軟體程式碼


    /// <summary>
    /// 全域性異常攔截中介軟體
    /// </summary>
    public class MyGlobalExceptionMiddleware
    {
        private readonly RequestDelegate _next;

        /// <summary>
        /// 注入下一個中介軟體
        /// </summary>
        public MyGlobalExceptionMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            try
            {
                // 等待下一個中介軟體執行完成
                await _next(httpContext);
            }
            // 異常時統一處理
            catch (Exception ex)
            {
                httpContext.Response.ContentType = "application/problem+json";

                ProblemDetails problem = new ProblemDetails
                {
                    Status = 500,
                    Title = "Exception: " + ex.Message
                };
                problem.Extensions.Add("message", ex.Message);
                if (!string.IsNullOrWhiteSpace(ex.StackTrace))
                {
                    // 自定義正則:匹配 at [方法名] in [檔案路徑]:line [行號]
                    var matches = Regex.Matches(ex.StackTrace, "at[ ](.+?)[ ]in[ ](.+?)[:]line[ ]([0-9]+)"); 
                    // 使用Linq的拓展方法,篩選出需要的資料
                    // 過濾掉:
                    //      1. 包含了當前中介軟體相關的異常
                    //      2. TODO:可以過濾掉ASPNetCore相關的異常。
                    var filterdMatches = matches.Where(t => !t.Groups[0].ToString().Contains("Middlewares.MyGlobalExceptionMiddleware"));
                    // 投影新的物件列表,方便呼叫者閱讀和使用
                    var extendExObject = filterdMatches.Select(x => new
                    {
                        method = x.Groups[1].ToString(),
                        file = x.Groups[2].ToString(),
                        line = x.Groups[3].ToString()
                    });
                    // 往problem物件新增一個拓展屬性detail
                    problem.Extensions.Add("detail", extendExObject);
                }

                // 暫時不清楚具體幹了什麼,表現上是把problem物件格式化到HTML文字中。
                var stream = httpContext.Response.Body;
                await JsonSerializer.SerializeAsync(stream, problem);
            }
        }
    }

註冊中介軟體

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // 註冊異常中介軟體(除此之外,全是.Net5 Api模板自動生成的程式碼)
            app.UseMiddleware<MyGlobalExceptionMiddleware>();
 
            // 感覺沒必要使用異常頁面,所以註釋了UseDeveloperExceptionPage
            if (env.IsDevelopment())
            {
                //app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AbpTest1 v1"));
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

控制器程式碼

    [ApiController]
    [Route("api/filter")]
    public class TestFilterController:ControllerBase
    {
        [HttpGet]
        public string TestFilterXXX()
        {
            throw new NotImplementedException();
            return "asdf";
        }
    }

Api呼叫結果

{
    "title": "Exception: The method or operation is not implemented.",
    "status": 500,
    "message": "The method or operation is not implemented.",
    "detail": [
        {
            "method": "AbpTest1.Controllers.TestFilterController.TestFilterXXX()",
            "file": "C:\\Users\\Administrator\\source\\repos\\AbpTest1\\AbpTest1\\Controllers\\TestFilterController.cs",
            "line": "14"
        }
    ]
}