Reputation: 20384
In my ASP.NET Core 3.1 application, there's code like this in the Startup class:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseStatusCodePagesWithReExecute("/error/{0}");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error/500");
app.UseHsts();
}
// ...
}
The ErrorController has an action like this:
public IActionResult Index(int id)
{
var context = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
var exception = context?.Error;
if (exception != null)
{
logger.LogCritical(exception, $"Unhandled exception in request {HttpContext.TraceIdentifier}: {exception.GetRecursiveMessage()}");
}
else
{
logger.LogCritical(exception, $"Unhandled exception in request {HttpContext.TraceIdentifier}, no exception available");
}
// ...
}
From what I've read, this should give me the unhandled exception that occurred in another action. But it doesn't. The exception object is null. I also tried using the other feature of type IExceptionHandlerFeature
but it's just the same. No exception anywhere.
How can I get the exception in the error handler?
Please note that I'm using the re-execute feature because I hate forwarding the user to a different URL in case of an error. That only makes things worse because reloading the page to "try again" will certainly never resolve any problem (it's the error page, after all, it can only ever show errors).
Upvotes: 5
Views: 5047
Reputation: 2797
This is a bug in .NET, up to .NET 7.
If you use app.UseDeveloperExceptionPage()
, then context.HttpContext.Features.Get<IExceptionHandlerFeature>()
will return null.
This appears to be fixed in .NET 8.
Upvotes: 1
Reputation: 8459
The StatusCodePages
middleware runs only if the response generated so far has no body.
If you want to catch exception in action, you could use a custom ExceptionHandler.
public class CustomExceptionHandler
{
private readonly IWebHostEnvironment _environment;
public CustomExceptionHandler(IWebHostEnvironment environment)
{
_environment = environment;
}
public async Task Invoke(HttpContext httpContext)
{
var feature = httpContext.Features.Get<IExceptionHandlerFeature>();
var error = feature?.Error;
if (error != null)
{
//LogError
}
await Task.CompletedTask;
}
}
startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseExceptionHandler(new ExceptionHandlerOptions
{
ExceptionHandler = new CustomExceptionHandler(env).Invoke
});
//...
}
Upvotes: 2
Reputation: 1577
To get the exception object you could use IExceptionHandlerFeature
public IActionResult Error()
{
// Retrieve error information in case of internal errors
var error = HttpContext
.Features
.Get<IExceptionHandlerFeature>();
if (error == null)
...
// Use the information about the exception
var exception = error.Error;
...
}
Upvotes: 4