I am creating a new API website in .NET8, which is the latest version of ASP.NET Core
In my program.cs I added this:
builder.Services.AddExceptionHandler<ErrorHandler>();
app.UseExceptionHandler("/Home/Error");
In case of an exception this goes indeed to my custom error handling class:
public class ErrorHandler : IExceptionHandler
I access the extra data I need like this:
private readonly ILogger<ErrorHandler> logger;
private readonly IHttpContextAccessor _httpContextAccessor;
public ErrorHandler(ILogger<ErrorHandler> logger, IHttpContextAccessor httpContextAccessor)
{
this.logger = logger;
this._httpContextAccessor = httpContextAccessor;
}
So far so good, but now I try to get some data for my log:
- Request URL
- Form data (RAW)
- Client IP Address
- Referrer
private string GetErrorReport(Exception e)
{
StringBuilder sbErrorReport = new StringBuilder(1024);
try
{
HttpResponse response = _httpContextAccessor.HttpContext?.Response;
HttpRequest request = _httpContextAccessor.HttpContext?.Request;
string CurUrl = "";
string CurReferrer = "";
string formData = "";
string clientIP = "";
if(request != null)
{
CurUrl = request.GetEncodedPathAndQuery();
CurReferrer = request.Headers["Referer"].ToString();
if(request.Body != null) //is this the same as request.Form.ToString()?
{
using (StreamReader sr = new StreamReader(request.Body))
{
formData = sr.ReadToEnd();
}
}
if(request.HttpContext != null && request.HttpContext.Connection != null && request.HttpContext.Connection.RemoteIpAddress != null)
{
clientIP = request.HttpContext.Connection.RemoteIpAddress.ToString();
}
}
}
catch (Exception ex)
{
//nothing?
}
return sbErrorReport.ToString();
}
None of them seem to work…
CurUrl gives "/Home/Error", not the original URL that had the error.
CurReferrer gives an error about headers not being available.
formData crashes completely.
clientIP actually seems to work, if ::1 is correct for localhost.
Any ideas how to best write errors with all these details to a log file?
2
Answers
After much help of Emre Bener, thank you for that, I figured it out. My mistake was to try to use the IHttpContextAccessor , whilst everything I needed was already in the TryHandleAsync from the IExceptionHandler.
Here is my code that works: In program.cs:
And in my general exception handling class ErrorHandler.cs:
In the error handler action, you can retrieve error details like this:
This will retrieve the error information from the current context. then, you can use
exceptionHandlerFeature.Error
to retrieve the actual error. for example:You can also read where the error occurred (request URL) from the
Path
property ofexceptionHandlerFeature
like this:HttpContext.Connection.RemoteIpAddress
will give you the client IP. In fact, you can get the current user like this:Note that you will have problems retrieving IP if your server is located behind a load balancer or if there is a proxy in place.
HttpContext.Request.Form
will give you the form data.Request.Headers["Referer"].ToString()
will give you the referrer header value.By the way, you can opt for using an inline handler for error handling, something like this:
see https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-8.0 for more info on error handling in asp.net core with the built-in error handler middleware.