处理asp.net核心中的异常?

Posted

技术标签:

【中文标题】处理asp.net核心中的异常?【英文标题】:Handling exception in asp.net core? 【发布时间】:2016-11-15 15:51:30 【问题描述】:

我有 asp.net 核心应用程序。 configure方法的实现在发生异常时将用户重定向到“错误”页面(在非开发环境中)

但是它只有在控制器内部发生异常时才有效。如果在控制器之外发生异常,例如在我的自定义中间件中,则用户不会被重定向到错误页面。

如果中间件出现异常,我如何将用户重定向到“错误”页面。

     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

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

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();
        app.UseSession();
        app.UseMyMiddleware();

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

更新 1 我用初始帖子中缺少的以下两行更新了上面的代码。

        app.UseSession();
        app.UseMyMiddleware();

我还发现了为什么app.UseExceptionHandler 无法重定向到错误页面。 当我的中间件代码出现异常时,app.UseExceptionHandler("\Home\Error") 按预期重定向到\Home\Error;但由于这是一个新请求,我的中间件再次执行并再次抛出异常。 所以为了解决这个问题,我改变了我的中间件只执行if context.Request.Path != "/Home/Error"

我不确定这是否是解决此问题的正确方法,但它的工作原理。

public class MyMiddleWare

    private readonly RequestDelegate _next;
    private readonly IDomainService _domainService;

    public MyMiddleWare(RequestDelegate next, IDomainService domain)
    
        _next = next;
        _domainService = domain;
    

    public async Task Invoke(HttpContext context)
    
        if (context.Request.Path != "/Home/Error")
        
            if (context.User.Identity.IsAuthenticated && !context.Session.HasKey(SessionKeys.USERINFO))
                       
                // this method may throw exception if domain service is down
                var userInfo = await _domainService.GetUserInformation(context.User.Name).ConfigureAwait(false);                    

                context.Session.SetUserInfo(userInfo);
            
        

        await _next(context);
    


public static class MyMiddleWareExtensions

    public static IApplicationBuilder UseMyMiddleWare(this IApplicationBuilder builder)
    
        return builder.UseMiddleware<MyMiddleWare>();
    
 

【问题讨论】:

您的自定义中间件在示例中的哪个位置?我认为 UseExeptionHandler 应该能够处理它,但是您的中间件需要在它之后注册 【参考方案1】:

你可以用UseExceptionHandler()来处理异常,把这段代码放在你的 Startup.cs.

UseExceptionHandler 可用于全局处理异常。您可以获得异常对象的所有详细信息,如堆栈跟踪、内部异常等。然后你可以在屏幕上显示它们。 Here

您可以在此处阅读有关此诊断中间件的更多信息,并了解如何使用 IExceptionFilter 以及创建您自己的自定义异常处理程序。

   app.UseExceptionHandler(
                options =>
                
                    options.Run(
                        async context =>
                        
                            context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
                            context.Response.ContentType = "text/html";
                            var ex = context.Features.Get<IExceptionHandlerFeature>();
                            if (ex != null)
                            
                                var err = $"<h1>Error: ex.Error.Message</h1>ex.Error.StackTrace";
                                await context.Response.WriteAsync(err).ConfigureAwait(false);
                            
                        );
                
            );

您还必须删除默认设置,如UseDeveloperExceptionPage(),如果您使用它,它总是显示默认错误页面。

   if (env.IsDevelopment())
        
            //This line should be deleted
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        
        else
        
            app.UseExceptionHandler("/Home/Error");
        

【讨论】:

我以前看过这篇文章。但是我认为问题在于,每当您将 response.StatusCode 设置为 500 时,浏览器都不会显示服务器发送的 html,而是浏览器显示其自己的代码 500 错误页面。在提琴手中,我看到响应正文有服务器的错误消息发送但浏览器不显示该错误消息。 只需从startup.cs中删除 app.UseDeveloperExceptionPage(); @LP13 你需要删除 app.UseDeveloperExceptionPage();它会起作用的。 我不认为这是我在帖子中所说的问题,它发生在非开发环境中 是否可以将 UseExceptionHandler 与默认错误页面一起使用?我想捕获错误详细信息,但保留现有行为和页面。【参考方案2】:

您应该编写自己的中间件来处理自定义异常处理。并确保将其添加到中间件堆栈的开头(如果可能,首先添加),因为堆栈中“较早”的中间件中发生的异常将不会被处理。

例子:

public class CustomExceptionMiddleware

    private readonly RequestDelegate _next;

    public CustomExceptionMiddleware(RequestDelegate next)
    
        _next = next;
    

    public async Task Invoke(HttpContext context)
    
        try 
        
            await _next.Invoke(context);
         
        catch (Exception e) 
        
            // Handle exception
        
    

【讨论】:

Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware 与您的建议完全相同。如果出现异常,此中间件会重定向到提供的路径。可以看代码github.com/aspnet/Diagnostics/blob/dev/src/…

以上是关于处理asp.net核心中的异常?的主要内容,如果未能解决你的问题,请参考以下文章

使用 ASP.net 核心(API 控制器)处理基本控制器中的异常

Asp.net MVC 之异常处理

ASP.NET MVC 处理区域中的请求验证异常

控制器中的异常处理 (ASP.NET MVC)

asp.net 核心中的红隼

从零写一个Asp.net core手脚架 (异常处理)