Last active
January 19, 2024 16:00
-
-
Save unseensenpai/691e8fc2a053e2c93a882d269c251956 to your computer and use it in GitHub Desktop.
Request Response Logging Middleware in .Net 8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
WebApplicationBuilder builder = WebApplication.CreateBuilder(args); | |
WebApplication app = builder.Build(); | |
app.UseRequestResponseLogging(); | |
app.Run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Core.Commons.Logging; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.AspNetCore.Http.Internal; | |
using System; | |
using System.IO; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Microsoft.Extensions.DependencyInjection | |
{ | |
public class RequestResponseLoggingMiddleware | |
{ | |
private readonly RequestDelegate _next; | |
public RequestResponseLoggingMiddleware(RequestDelegate next) | |
{ | |
_next = next; | |
} | |
public async Task Invoke(HttpContext context) | |
{ | |
// LOG REQUEST | |
Logger.Info(await FormatRequest(context.Request)); | |
var originalBodyStream = context.Response.Body; | |
using (var responseBody = new MemoryStream()) | |
{ | |
context.Response.Body = responseBody; | |
// WAIT FOR RESPONSE | |
await _next(context); | |
// LOG RESPONSE | |
Logger.Info(await FormatResponse(context.Response)); | |
if (context.Response.StatusCode != 204) | |
{ | |
await responseBody.CopyToAsync(originalBodyStream); | |
} | |
} | |
} | |
/// <summary> | |
/// Returns the destination path in the Http request, the query if any, and the first 100 characters in the body if any, as a string to log. | |
/// </summary> | |
/// <param name="request">Http request instance</param> | |
/// <returns></returns> | |
private static async Task<string> FormatRequest(HttpRequest request) | |
{ | |
try | |
{ | |
request.EnableBuffering(); | |
var body = request.Body; | |
var buffer = new byte[Convert.ToInt32(request.ContentLength)]; | |
await request.Body.ReadAsync(buffer, 0, buffer.Length); | |
var bodyAsText = Encoding.UTF8.GetString(buffer); | |
body.Seek(0, SeekOrigin.Begin); | |
request.Body = body; | |
return $"{request.Scheme}://{request.Host}{request.Path}" + | |
(!string.IsNullOrEmpty(request.QueryString.ToString()) ? $" - QUERY: {request.QueryString}" : string.Empty) + | |
(!string.IsNullOrEmpty(bodyAsText) ? (bodyAsText.Length < 100 ? $" - BODY: {bodyAsText}" : $" - BODY: {bodyAsText[..98]}..") : string.Empty); | |
} | |
catch (Exception ex) | |
{ | |
return $"ERROR: {ex.Message} - METHOD: RequestResponseLoggingMiddleware.FormatRequest()"; | |
} | |
} | |
/// <summary> | |
/// Returns the status code from the http response and the first 100 characters in the body if any, as a string to log. | |
/// </summary> | |
/// <param name="response">Outgoing side of Http request instance</param> | |
/// <returns></returns> | |
private static async Task<string> FormatResponse(HttpResponse response) | |
{ | |
try | |
{ | |
response.Body.Seek(0, SeekOrigin.Begin); | |
string text = await new StreamReader(response.Body).ReadToEndAsync(); | |
response.Body.Seek(0, SeekOrigin.Begin); | |
return $"Response {response.StatusCode}" + | |
(!string.IsNullOrEmpty(text) ? (text.Length < 100 ? $" - BODY: {text}" : $" - BODY: {text[..98]}..") : string.Empty); | |
} | |
catch (Exception ex) | |
{ | |
return $"ERROR: {ex.Message} - METHOD: RequestResponseLoggingMiddleware.FormatResponse()"; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Builder; | |
namespace Microsoft.Extensions.DependencyInjection | |
{ | |
public static class RequestResponseLoggingMiddlewareExtensions | |
{ | |
public static IApplicationBuilder UseRequestResponseLogging(this IApplicationBuilder builder) | |
{ | |
return builder.UseMiddleware<RequestResponseLoggingMiddleware>(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment