ASP.NET Core MVC(2.2)错误中间件未触发错误页面

时间:2019-12-03 15:24:24

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

在我的ASP.NET Core MVC(2.2)应用程序中,我已经完成了全局错误处理类的设置。我通过在app.UseMiddleware()之前使用app.UseMvc()在项目的Startup.cs中注入此类。但是,当我将Response.StatusCode设置为相应的代码(400,404,500)并返回响应 Error时,此错误处理程序将像应该发生的那样触发于每个异常页面控制器没有被调用。但是,如果我从控制器手动返回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.
    }
 }

1 个答案:

答案 0 :(得分: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;
        }
    }
}