首页 > 解决方案 > ASP.NET Core MVC (2.2) 错误中间件未触发错误页面

问题描述

在我的 ASP.NET Core MVC (2.2) 应用程序中,我已经完成了全局错误处理类的设置。我通过app.UseMiddleware()app.UseMvc(). 这个错误处理程序会在每个异常上触发,但是,当我将 设置Response.StatusCode为相应的代码(400、404、500)并返回响应时,错误页面控制器不会被调用。但是,如果我从控制器手动返回 a ,则会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.netasp.net-coreasp.net-core-mvc

解决方案


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

是的。尝试修改您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;
        }
    }
}

推荐阅读