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

Cenk 1,031 Reputation points
2022-12-29T06:45:58.67+00:00

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());  
        }  
    }  
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,815 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.