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.
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 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.
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.
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 useOnPost
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With