CorrelationIdMiddleware
public class CorrelationIdMiddleware
{
private readonly RequestDelegate _next;
public CorrelationIdMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
// Generate or retrieve existing correlation ID
var correlationId = context.Request.Headers["X-Correlation-ID"].FirstOrDefault() ?? Guid.NewGuid().ToString();
// Store it in HttpContext for downstream access
context.Items["CorrelationId"] = correlationId;
// Optionally, push it into logging scope for automatic inclusion in logs
using (LogContext.PushProperty("CorrelationId", correlationId))
{
await _next(context);
}
}
}
Extract from payload
public class CorrelationIdMiddleware
{
private readonly RequestDelegate _next;
public CorrelationIdMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
string correlationId = null;
// Enable request body buffering
context.Request.EnableBuffering();
using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, leaveOpen: true))
{
var body = await reader.ReadToEndAsync();
if (!string.IsNullOrWhiteSpace(body))
{
// Deserialize JSON payload to extract correlationId
var requestData = JsonSerializer.Deserialize<Dictionary<string, string>>(body);
if (requestData != null && requestData.ContainsKey("CorrelationId"))
{
correlationId = requestData["CorrelationId"];
}
}
}
// Reset request body position for downstream processing
context.Request.Body.Position = 0;
// Use header fallback if correlationId is not found in payload
correlationId ??= context.Request.Headers["X-Correlation-ID"].FirstOrDefault() ?? Guid.NewGuid().ToString();
// Store correlationId in HttpContext
context.Items["CorrelationId"] = correlationId;
// Push Correlation ID to logging scope
using (LogContext.PushProperty("CorrelationId", correlationId))
{
var correlationId = HttpContext.Items["CorrelationId"]?.ToString();
_logger.LogInformation("Processing request with CorrelationId: {CorrelationId}", correlationId);
await _next(context);
}
}
}
setup with serilog
dotnet add package Serilog.Formatting.Compact
using Serilog;
using Serilog.Formatting.Compact;
var logger = new LoggerConfiguration()
.Enrich.WithCorrelationId()
.WriteTo.Console(new RenderedCompactJsonFormatter()) // Outputs JSON logs to console
.WriteTo.File("logs.json", formatter: new RenderedCompactJsonFormatter()) // Saves logs to a file
.CreateLogger();
Log.Logger = logger;
Override Mictrosoft and system logs
var logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning) // Suppress Microsoft logs
.MinimumLevel.Override("System", Serilog.Events.LogEventLevel.Warning) // Suppress System logs
.WriteTo.Console()
.CreateLogger();
Log.Logger = logger;
OR
.MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", Serilog.Events.LogEventLevel.Error)
builder.Logging.ClearProviders();
builder.Host.UseSerilog(logger);