ASP.NET Core中,UseDeveloperExceptionPage擴展方法會吃掉異常


在ASP.NET Core中Startup類的Configure方法中,有一個擴展方法叫UseDeveloperExceptionPage,如下所示:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();     }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

UseDeveloperExceptionPage方法是所屬DeveloperExceptionPageExtensions類的IApplicationBuilder擴展方法,這個方法是新建ASP.NET Core項目時默認加入Startup類中的,它的作用是ASP.NET Core在開發環境(Development環境)下用於展示異常信息頁面,如下所示:

但是UseDeveloperExceptionPage方法有一個很坑的特性,那就是它會吃掉ASP.NET Core中Middleware管道中的異常。

 

我們來設想,假如我們定義了下面一個Middleware叫LoggerMiddleware,它使用try catch代碼塊,來記錄所有發生在ASP.NET Core的Middleware管道中拋出的異常到日志:

public class LoggerMiddleware
{
    private readonly RequestDelegate next;

    public LoggerMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(
        Microsoft.AspNetCore.Http.HttpContext context)
    {
        Logger logger = LogManager.GetCurrentClassLogger();
        //logger.Log(NLog.LogLevel.Info, "Log tracking start!");

        try
        {
            await next.Invoke(context);
        }
        catch (Exception ex)
        {
            LogMessageGenerator logMessageGenerator = new LogMessageGenerator(() =>
            {
                return ex.GetType().FullName + "\r\n" + ex.StackTrace;
            });

            logger.Log(NLog.LogLevel.Error, ex, logMessageGenerator);
            throw;
        }

        //logger.Log(NLog.LogLevel.Info, "Log tracking end!");
    }
}

還有其擴展類LoggerMiddlewareExtension:

public static class LoggerMiddlewareExtension
{
    public static void UsePipelineLogger(this IApplicationBuilder app)
    {
        app.UseMiddleware<LoggerMiddleware>();
    }
}

 

然后我在ASP.NET Core中Startup類的Configure方法中,將其(app.UsePipelineLogger)放在app.UseDeveloperExceptionPage方法前面:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UsePipelineLogger();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

然后你會發現當MVC Controller中拋出異常時,LoggerMiddleware中的try catch代碼塊捕獲不到任何異常。最開始我相當納悶,這異常怎么活生生地就被吃掉了呢?

后來我在ASP.NET Core中Startup類的Configure方法中,將app.UsePipelineLogger放在了app.UseDeveloperExceptionPage后面:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UsePipelineLogger();

    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

這下LoggerMiddleware中的try catch代碼塊就成功捕獲到了MVC Controller中拋出的異常,這很明確地證明了是app.UseDeveloperExceptionPage方法的Middleware吃掉了ASP.NET Core管道中的異常。

 

雖然不知道app.UseExceptionHandler方法是不是也會吃掉異常,但是建議大家把捕獲異常的Middleware(本例的app.UsePipelineLogger)方法,都放在app.UseDeveloperExceptionPage和app.UseExceptionHandler的后面!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM