ASP.NET Core Web API - Why it does not log internal server error?

Cenk
1,031
Reputation points
Hi,
According to your directions and help, I implemented a global exception middleware and a request-response middleware. The request-response middleware does not log internal server errors. I do want to log internal server error, how can I achieve it?
The request-response middleware:
public class RequestResponseMiddleware
{
private readonly RequestDelegate _next;
private readonly IConfiguration _configuration;
private readonly bool _isRequestResponseLoggingEnabled;
public RequestResponseMiddleware(RequestDelegate next, IConfiguration configuration)
{
_next = next;
_configuration = configuration;
_isRequestResponseLoggingEnabled = configuration.GetValue<bool>("EnableRequestResponseLogging", true);
}
public async Task InvokeAsync(HttpContext httpContext)
{
// Middleware is enabled only when the EnableRequestResponseLogging config value is set.
if (_isRequestResponseLoggingEnabled)
{
await using var sqlConnection =
new SqlConnection(_configuration.GetSection("ConnectionStrings:OyunPalasDbContext").Value);
await using var cmd =
new SqlCommand(
"INSERT INTO [dbo].[API_Log] ([Host],[Headers],[StatusCode],[TimeUtc],[RequestBody],[RequestedMethod],[UserHostAddress],[Useragent],[AbsoluteUri],[RequestType]) VALUES (@Host,@Headers,@StatusCode,getdate(),@RequestBody,@RequestedMethod,@UserHostAddress,@Useragent,@AbsoluteUri,@RequestType)",
sqlConnection);
sqlConnection.Open();
cmd.Parameters.AddWithValue("@Host", httpContext.Request.Host.ToString());
cmd.Parameters.AddWithValue("@StatusCode", "");
cmd.Parameters.AddWithValue("@Headers", FormatHeaders(httpContext.Request.Headers));
cmd.Parameters.AddWithValue("@RequestBody", await ReadBodyFromRequest(httpContext.Request));
cmd.Parameters.AddWithValue("@RequestedMethod", httpContext.Request.Method);
cmd.Parameters.AddWithValue("@UserHostAddress", httpContext.Request.Host.ToString());
cmd.Parameters.AddWithValue("@Useragent", httpContext.Request.Headers["User-Agent"].ToString());
cmd.Parameters.AddWithValue("@AbsoluteUri", httpContext.Request.Path.ToString());
cmd.Parameters.AddWithValue("@RequestType", "Request");
cmd.ExecuteNonQuery();
//Console.WriteLine($"-------HTTP request information:\n" +
// $"\tMethod: {httpContext.Request.Method}\n" +
// $"\tPath: {httpContext.Request.Path}\n" +
// $"\tQueryString: {httpContext.Request.QueryString}\n" +
// $"\tHeaders: {FormatHeaders(httpContext.Request.Headers)}\n" +
// $"\tSchema: {httpContext.Request.Scheme}\n" +
// $"\tHost: {httpContext.Request.Host}\n" +
// $"\tBody: {await ReadBodyFromRequest(httpContext.Request)}");
// Temporarily replace the HttpResponseStream, which is a write-only stream, with a MemoryStream to capture it's value in-flight.
var originalResponseBody = httpContext.Response.Body;
using var newResponseBody = new MemoryStream();
httpContext.Response.Body = newResponseBody;
// Call the next middleware in the pipeline
await _next(httpContext);
newResponseBody.Seek(0, SeekOrigin.Begin);
var responseBodyText = await new StreamReader(httpContext.Response.Body).ReadToEndAsync();
await using var sqlConnectionResponse =
new SqlConnection(_configuration.GetSection("ConnectionStrings:OyunPalasDbContext").Value);
await using var cmdResponse =
new SqlCommand(
"INSERT INTO [dbo].[API_Log] ([Host],[Headers],[StatusCode],[TimeUtc],[RequestBody],[RequestedMethod],[UserHostAddress],[Useragent],[AbsoluteUri],[RequestType]) VALUES (@Host,@Headers,@StatusCode,getdate(),@RequestBody,@RequestedMethod,@UserHostAddress,@Useragent,@AbsoluteUri,@RequestType)",
sqlConnectionResponse);
sqlConnectionResponse.Open();
cmdResponse.Parameters.AddWithValue("@Host", httpContext.Request.Host.ToString());
cmdResponse.Parameters.AddWithValue("@Headers", FormatHeaders(httpContext.Response.Headers));
cmdResponse.Parameters.AddWithValue("@StatusCode", httpContext.Response.StatusCode.ToString());
cmdResponse.Parameters.AddWithValue("@RequestBody", responseBodyText);
cmdResponse.Parameters.AddWithValue("@RequestedMethod", httpContext.Request.Method);
cmdResponse.Parameters.AddWithValue("@UserHostAddress", httpContext.Request.Host.ToString());
cmdResponse.Parameters.AddWithValue("@Useragent", "");
cmdResponse.Parameters.AddWithValue("@AbsoluteUri","");
cmdResponse.Parameters.AddWithValue("@RequestType", "Response");
cmdResponse.ExecuteNonQuery();
//Console.WriteLine($"-------HTTP response information:\n" +
// $"\tStatusCode: {httpContext.Response.StatusCode}\n" +
// $"\tContentType: {httpContext.Response.ContentType}\n" +
// $"\tHeaders: {FormatHeaders(httpContext.Response.Headers)}\n" +
// $"\tBody: {responseBodyText}");
newResponseBody.Seek(0, SeekOrigin.Begin);
await newResponseBody.CopyToAsync(originalResponseBody);
}
else
{
await _next(httpContext);
}
}
private static async Task<string> ReadBodyFromRequest(HttpRequest request)
{
// Ensure the request's body can be read multiple times (for the next middlewares in the pipeline).
request.EnableBuffering();
using var streamReader = new StreamReader(request.Body, leaveOpen: true);
var requestBody = await streamReader.ReadToEndAsync();
// Reset the request's body stream position for next middleware in the pipeline.
request.Body.Position = 0;
return requestBody;
}
private static string FormatHeaders(IHeaderDictionary headers) => string.Join(", ", headers.Select(kvp => $"{<!-- -->{<!-- -->{kvp.Key}: {string.Join(", ", kvp.Value)}}}"));
}
The exception middleware
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private static IConfiguration _configuration;
public ExceptionMiddleware(RequestDelegate next, IConfiguration configuration)
{
_next = next;
_configuration = configuration;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
await HandleExceptionAsync(httpContext, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
try
{
await using var sqlConnection =
new SqlConnection(_configuration.GetSection("ConnectionStrings:OyunPalasDbContext").Value);
await using var cmd =
new SqlCommand(
"INSERT INTO [dbo].[APIError] ([Message],[RequestMethod],[RequestUri],[TimeUtc]) VALUES (@Message, @RequestMethod, @RequestUri, @TimeUtc)",
sqlConnection);
sqlConnection.Open();
cmd.Parameters.AddWithValue("@Message", exception.Message);
cmd.Parameters.AddWithValue("@TimeUtc", DateTime.Now);
cmd.Parameters.AddWithValue("@RequestUri", context.Request.Path.ToString());
cmd.Parameters.AddWithValue("@RequestMethod", context.Request.Method.ToString());
if (exception.InnerException != null)
{
cmd.Parameters.AddWithValue("@Message", exception.Message +" " + exception.InnerException);
}
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
Console.WriteLine(e);
}
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await context.Response.WriteAsync(new ErrorDetails()
{
StatusCode = context.Response.StatusCode,
Message = "Internal Server Error."
}.ToString());
}
}
Sign in to answer