Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core returns 404 instead of 500 when using ExceptionHandler PipeLine

I have this controller

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        Console.WriteLine("GET Index");
        throw new Exception();
    }

    // POST api/values
    [HttpPost]
    public void Post()
    {
        Console.WriteLine("POST Index");
        throw new Exception();
    }
}

Both the GET and POST request returns a statuscode of 500. This is the expected behavior.

But when I add app.UseExceptionHandler("/api/debug/error"); In the Startup.cs file, the POST request does no longer return a statuscode of 500, instead it returns 404. The GET request is still working as it should by returning a statuscode of 500.

DebugController

[Route("api/[controller]")]
public class DebugController : Controller
{


    [HttpGet("error")]
    public IActionResult Index()
    {
        return StatusCode(500,"Hello, World! From debug controller");
    }
}

Any idé why adding app.UseExceptionHandler("/api/debug/error"); would make the POST request behave this way?

A repo to reproduce this behavior can be found Here.

like image 570
zexuz Avatar asked Feb 07 '18 15:02

zexuz


People also ask

How do you handle exceptions in middleware NET Core?

The exception handling middleware re-executes the request using the original HTTP method. If an error handler endpoint is restricted to a specific set of HTTP methods, it runs only for those HTTP methods. For example, an MVC controller action that uses the [HttpGet] attribute runs only for GET requests.

How do I handle exceptions in ASP.NET Core Web API?

To handle exceptions we can use the try-catch block in our code as well as finally keyword to clean up resources afterward. Even though there is nothing wrong with the try-catch blocks in our Actions in Web API project, we can extract all the exception handling logic into a single centralized place.

How does Web API handle global exception in .NET Core?

The middleware UseExceptionHandler can be used to handle exceptions globally. You can get all the details of the exception object (Stack Trace, Inner exception, message etc..) and display them on-screen. You can implement like this.


1 Answers

When using ExceptionHandlerMiddleware with an ExceptionHandlingPath, as in your example, the main outcome is that the request path gets rewritten to instead use your new path (/api/debug/error in your case). You can see how this works in the source:

if (_options.ExceptionHandlingPath.HasValue)
{
    context.Request.Path = _options.ExceptionHandlingPath;
}

If you continue to browse through the source, you'll see that the StatusCode gets set to 500, but the original request is left mostly intact.

In practical terms, this means you are being sent to a POST action on your DebugController, but you have only provided a GET action.

A simple way to fix this would be to make your Index action support both GET and POST, like so:

[HttpGet("error")]
[HttpPost("error")]
public IActionResult Index()
{
    return StatusCode(500,"Hello, World! From debug controller");
}

If you want to do something different for POST errors, you can just create a new action, decorated with [HttpPost("error")].


Update: Some of this explanation now exists in the docs:

The exception handling middleware re-executes the request using the original HTTP method. If an error handler endpoint is restricted to a specific set of HTTP methods, it runs only for those HTTP methods. For example, an MVC controller action that uses the [HttpGet] attribute runs only for GET requests. To ensure that all requests reach the custom error handling page, don't restrict them to a specific set of HTTP methods.

To handle exceptions differently based on the original HTTP method:

  • For Razor Pages, create multiple handler methods. For example, use OnGet to handle GET exceptions and use OnPost to handle POST exceptions.
  • For MVC, apply HTTP verb attributes to multiple actions. For example, use [HttpGet] to handle GET exceptions and use [HttpPost] to handle POST exceptions.
like image 167
Kirk Larkin Avatar answered Oct 17 '22 03:10

Kirk Larkin