【问题标题】:ASP.NET Core MVC (2.2) Error Middle-ware not triggering error pagesASP.NET Core MVC (2.2) 错误中间件未触发错误页面
【发布时间】:2019-12-03 15:24:24
【问题描述】:

在我的 ASP.NET Core MVC (2.2) 应用程序中,我已经完成了全局错误处理类的设置。我通过在app.UseMvc() 之前使用app.UseMiddleware() 将这个类注入到我的项目的Startup.cs 中。但是,当我将 Response.StatusCode 设置为相应的代码 (400, 404, 500) 并返回 错误页面控制器的响应时,此错误处理程序会像它应该那样被触发 不会被调用。但是,如果我从控制器手动返回BadRequest();,则会调用错误页面控制器。

甚至可以从错误处理程序中间件类触发错误页面吗?如果是这样,我该如何实现这种行为?

这是我的错误处理中间件类。

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate nextDelegate;

    public ErrorHandlingMiddleware(RequestDelegate nextDelegate)
    {
        this.nextDelegate = nextDelegate;
    }

    public async Task Invoke(HttpContext context, IOptions<MvcJsonOptions> options)
    {
        try
        {
            await this.nextDelegate(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex, options);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception ex, IOptions<MvcJsonOptions> options)
    {
        var httpStatusCode = HttpStatusCode.InternalServerError;

        if (ex is CommonApiException commonApiException)
        {
            httpStatusCode = (HttpStatusCode)commonApiException.StatusCode;
        }

        var result = JsonConvert.SerializeObject(new { error = ex.Message }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)httpStatusCode;

        return context.Response.WriteAsync(result);
    }
}

我的启动配置

public void Configure(
        IApplicationBuilder app,
        IHostingEnvironment environment,
        ILogger<Startup> logger,
        ILoggerFactory factory)
    {            
        app.UseExceptionHandler("/Error");
        app.UseStatusCodePagesWithReExecute("/Error/StatusCode/{0}");
        // ....

        // .... 
        app.UseMiddleware(typeof(ErrorHandlingMiddleware));
        app.UseMvc();
    }

错误页面控制器

public class ErrorController : Controller
{       
    [AllowAnonymous]
    [Route("Error")]
    [Route("Error/Index")]
    [Route("Error/500")]
    [SkipFilters("Bypass claims.")]
    public IActionResult Index()
    {
        return this.View();
    }

    [AllowAnonymous]
    [SkipFilters("Bypass claims.")]
    [Route("Error/StatusCode/{code}")]
    public IActionResult ErrorStatusCode(int code)
    {
        var statusCodeModel = new StatusCodeModel
        {
            ErrorStatusCode = code.ToString(),
            OperationId = Activity.Current.RootId
        };

        var statusCodeReExecuteFeature = this.HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
        if (statusCodeReExecuteFeature != null)
        {
            statusCodeModel.OriginalUrl =
                statusCodeReExecuteFeature.OriginalPathBase
                + statusCodeReExecuteFeature.OriginalPath
                + statusCodeReExecuteFeature.OriginalQueryString;
        }

        return this.View("StatusCode", statusCodeModel);
    }
}

我用于测试的控制器

 public class DummyController : Controller
    {

    [Route("Dummy")]
    public IActionResult Dummy()
    {
        throw new CommonApiException("Test Error");

        //return this.BadRequest(); //This triggers the error page controller.
    }
 }

【问题讨论】:

    标签: c# asp.net asp.net-core asp.net-core-mvc


    【解决方案1】:

    甚至可以从错误处理程序中间件类触发错误页面吗?如果是这样,我该如何实现这种行为?

    是的。尝试修改您的HandleExceptionAsync ErrorHandlingMiddleware 以重写您的网址:

    public class ErrorHandlingMiddleware
    {
        private readonly RequestDelegate nextDelegate;
    
        public ErrorHandlingMiddleware(RequestDelegate nextDelegate)
        {
            this.nextDelegate = nextDelegate;
        }
    
        public async Task Invoke(HttpContext context, IOptions<MvcJsonOptions> options)
        {
            try
            {
                await this.nextDelegate(context);
            }
            catch (Exception ex)
            {
                await HandleExceptionAsync(context, ex, options);
            }
        }
    
        private async Task HandleExceptionAsync(HttpContext context, Exception ex, IOptions<MvcJsonOptions> options)
        {
            var httpStatusCode = HttpStatusCode.InternalServerError;
    
            PathString originalPath = context.Request.Path;
            context.Request.Path = "/Error/StatusCode" + (int)httpStatusCode;
            try
            {
                var exceptionHandlerFeature = new ExceptionHandlerFeature()
                {
                    Error = ex,
                    Path = originalPath.Value,
                };
                context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
                context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
                context.Response.StatusCode = (int)httpStatusCode;
    
                await this.nextDelegate(context);
                return;
            }
            catch (Exception ex2)
            {
            }
            finally
            {
                context.Request.Path = originalPath;
            }
        }
    }
    

    【讨论】:

    • 为什么会有 finally 块?将请求路径设置为原始路径的目的是什么?
    • @Adrian Cruz 它将在try 块中返回,finally 块在您有错误时使用并且不会更改当前请求路径。由您决定如何编写。
    • 谢谢。您的解决方案完美运行!我会将此标记为答案。
    猜你喜欢
    • 2019-09-21
    • 1970-01-01
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 2015-06-22
    • 2018-08-05
    • 1970-01-01
    相关资源
    最近更新 更多