'ASP.NET Core MVC (2.2) Error Middle-ware not triggering error pages

In my ASP.NET Core MVC (2.2) app I have completed the setup for a global error handling class. I inject this class in the Startup.cs of my project by using app.UseMiddleware() right before the app.UseMvc(). This error handler gets triggered on every exception like it should, however, when I set the Response.StatusCode to the corresponding code (400, 404, 500) and return the response the Error Page controller doesn't get called. However, if I manually return a BadRequest(); from my controller(s) the Error Page controller gets called.

Is it even possible to trigger error pages from a error handler middle ware class? If so, how can I achieve such behavior?

Here is my Error Handling Middle ware Class.

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);
    }
}

My Startup configuration

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();
    }

Error Page controller

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);
    }
}

Controller I am using for testing

 public class DummyController : Controller
    {

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

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


Solution 1:[1]

Is it even possible to trigger error pages from a error handler middle ware class? If so, how can I achieve such behavior?

Yes.Try to modify your HandleExceptionAsync ErrorHandlingMiddleware to rewrite your url:

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;
            context.SetEndpoint(null);

            await this.nextDelegate(context);
            return;
        }
        catch (Exception ex2)
        {
        }
        finally
        {
            context.Request.Path = originalPath;
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 nZeus