Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public static class Headers
public const string Pagination = "X-Pagination";
public const string Authorization = "Authorization";
public const string Idempotency = "Idempotency-Key";
public const string Correlation = "Correlation";
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public static void AddHttpClients(this IServiceCollection services)

// registers the header propagation service
// essential for receiving an authenticated request and forwarding it to another service
services.AddTransient<CorrelationInterceptor>();
services.AddHeaderPropagation(options =>
{
options.Headers.Add(Headers.Authorization);
Expand Down Expand Up @@ -63,14 +64,27 @@ public static void AddHttpClients(this IServiceCollection services)
});

customersClient.AddHeaderPropagation();
customersClient.AddHttpMessageHandler<CorrelationInterceptor>();

ownersClient.AddHeaderPropagation();
ownersClient.AddHttpMessageHandler<CorrelationInterceptor>();

paymentsClient.AddHeaderPropagation();
paymentsClient.AddHttpMessageHandler<CorrelationInterceptor>();

storesClient.AddHeaderPropagation();
storesClient.AddHttpMessageHandler<CorrelationInterceptor>();

productsClient.AddHeaderPropagation();
productsClient.AddHttpMessageHandler<CorrelationInterceptor>();

subscriptionsClient.AddHeaderPropagation();
subscriptionsClient.AddHttpMessageHandler<CorrelationInterceptor>();

ordersClient.AddHeaderPropagation();
ordersClient.AddHttpMessageHandler<CorrelationInterceptor>();

credentialsClient.AddHeaderPropagation();
credentialsClient.AddHttpMessageHandler<CorrelationInterceptor>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public static void UseHttpPipeline(this IApplicationBuilder app)
app.UseAuthorization();

app.UsePrincipalMiddleware();
app.UseCorrelationMiddleware();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Comanda.Orchestrator.WebApi.Interceptors;

public sealed class CorrelationInterceptor(IHttpContextAccessor accessor) : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var correlation = accessor.HttpContext?.Items[Headers.Correlation]?.ToString();

if (!string.IsNullOrWhiteSpace(correlation))
{
request.Headers.Remove(Headers.Correlation);
request.Headers.Add(Headers.Correlation, correlation);
}

return await base.SendAsync(request, cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Comanda.Orchestrator.WebApi.Middlewares;

public sealed class CorrelationMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
var correlationId = context.Request.Headers[Headers.Correlation].FirstOrDefault();

if (string.IsNullOrWhiteSpace(correlationId))
correlationId = context.TraceIdentifier;

context.Items[Headers.Correlation] = correlationId;
context.Response.Headers[Headers.Correlation] = correlationId;

/* enriches the logging scope with the current correlation identifier, ensuring all logs within this request pipeline share the same identifier */
/* more details: https://microsoft.github.io/code-with-engineering-playbook/observability/correlation-id/ */

using (LogContext.PushProperty(Headers.Correlation, correlationId))
using (SentrySdk.PushScope())
{
SentrySdk.ConfigureScope(scope =>
{
scope.SetTag("correlation_id", correlationId);
});

await next(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Comanda.Orchestrator.WebApi.Middlewares;

[ExcludeFromCodeCoverage(Justification = "contains only dependency injection")]
public static class CorrelationMiddlewareExtension
{
public static IApplicationBuilder UseCorrelationMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<CorrelationMiddleware>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
global using Comanda.Orchestrator.WebApi.Extensions;
global using Comanda.Orchestrator.WebApi.Constants;
global using Comanda.Orchestrator.WebApi.Middlewares;
global using Comanda.Orchestrator.WebApi.Interceptors;
global using Comanda.Orchestrator.WebApi.Providers;

global using Comanda.Orchestrator.Application.Payloads.Payments;
Expand All @@ -38,5 +39,6 @@

global using Scalar.AspNetCore;
global using Serilog;
global using Serilog.Context;
global using FluentValidation.AspNetCore;

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Comanda.Orders.WebApi.Constants;

public static class Headers
{
public const string Credential = "X-Credential";
public const string Location = "Location";
public const string Link = "Link";
public const string Pagination = "X-Pagination";
public const string Authorization = "Authorization";
public const string Idempotency = "Idempotency-Key";
public const string Correlation = "Correlation";
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static void UseHttpPipeline(this IApplicationBuilder app)
app.UseAuthentication();
app.UseAuthorization();

app.UseCorrelationMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Comanda.Orders.WebApi.Middlewares;

public sealed class CorrelationMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
var correlationId = context.Request.Headers[Headers.Correlation].FirstOrDefault();

if (string.IsNullOrWhiteSpace(correlationId))
correlationId = context.TraceIdentifier;

context.Items[Headers.Correlation] = correlationId;
context.Response.Headers[Headers.Correlation] = correlationId;

/* enriches the logging scope with the current correlation identifier, ensuring all logs within this request pipeline share the same identifier */
/* more details: https://microsoft.github.io/code-with-engineering-playbook/observability/correlation-id/ */

using (LogContext.PushProperty(Headers.Correlation, correlationId))
using (SentrySdk.PushScope())
{
SentrySdk.ConfigureScope(scope =>
{
scope.SetTag("correlation_id", correlationId);
});

await next(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Comanda.Orders.WebApi.Middlewares;

[ExcludeFromCodeCoverage(Justification = "contains only dependency injection")]
public static class CorrelationMiddlewareExtension
{
public static IApplicationBuilder UseCorrelationMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<CorrelationMiddleware>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

global using Comanda.Orders.WebApi.Extensions;
global using Comanda.Orders.WebApi.Constants;
global using Comanda.Orders.WebApi.Middlewares;
global using Comanda.Orders.Domain.Errors;

global using Comanda.Orders.Application.Payloads.Order;
Expand All @@ -21,4 +22,5 @@

global using Scalar.AspNetCore;
global using Serilog;
global using Serilog.Context;
global using FluentValidation.AspNetCore;
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@
public static class Headers
{
public const string Credential = "X-Credential";
public const string Location = "Location";
public const string Link = "Link";
public const string Pagination = "X-Pagination";
public const string Authorization = "Authorization";
public const string Idempotency = "Idempotency-Key";
public const string Correlation = "Correlation";
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public static void AddHttpClients(this IServiceCollection services, ISettings se
// register transient lifetime interceptors here
// https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/httpclient-parameters-handlers
services.AddTransient<CredentialInterceptor>();
services.AddTransient<CorrelationInterceptor>();

var paymentClient = services.AddHttpClient<IAbacatePayClient, AbacatePayClient>(client =>
{
Expand All @@ -16,5 +17,6 @@ public static void AddHttpClients(this IServiceCollection services, ISettings se
});

paymentClient.AddHttpMessageHandler<CredentialInterceptor>();
paymentClient.AddHttpMessageHandler<CorrelationInterceptor>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static void UseHttpPipeline(this IApplicationBuilder app)
app.UseAuthentication();
app.UseAuthorization();

app.UseCorrelationMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Comanda.Payments.WebApi.Interceptors;

public sealed class CorrelationInterceptor(IHttpContextAccessor accessor) : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var correlation = accessor.HttpContext?.Items[Headers.Correlation]?.ToString();

if (!string.IsNullOrWhiteSpace(correlation))
{
request.Headers.Remove(Headers.Correlation);
request.Headers.Add(Headers.Correlation, correlation);
}

return await base.SendAsync(request, cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Comanda.Payments.WebApi.Middlewares;

public sealed class CorrelationMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
var correlationId = context.Request.Headers[Headers.Correlation].FirstOrDefault();

if (string.IsNullOrWhiteSpace(correlationId))
correlationId = context.TraceIdentifier;

context.Items[Headers.Correlation] = correlationId;
context.Response.Headers[Headers.Correlation] = correlationId;

/* enriches the logging scope with the current correlation identifier, ensuring all logs within this request pipeline share the same identifier */
/* more details: https://microsoft.github.io/code-with-engineering-playbook/observability/correlation-id/ */

using (LogContext.PushProperty(Headers.Correlation, correlationId))
using (SentrySdk.PushScope())
{
SentrySdk.ConfigureScope(scope =>
{
scope.SetTag("correlation_id", correlationId);
});

await next(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Comanda.Payments.WebApi.Middlewares;

[ExcludeFromCodeCoverage(Justification = "contains only dependency injection")]
public static class CorrelationMiddlewareExtension
{
public static IApplicationBuilder UseCorrelationMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<CorrelationMiddleware>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
global using Comanda.Payments.WebApi.Constants;
global using Comanda.Payments.WebApi.Interceptors;
global using Comanda.Payments.WebApi.Extensions;
global using Comanda.Payments.WebApi.Middlewares;
global using Comanda.Payments.Domain.Errors;

global using Comanda.Payments.Application.Payloads.Traceability;
Expand All @@ -25,4 +26,5 @@

global using Scalar.AspNetCore;
global using Serilog;
global using Serilog.Context;
global using FluentValidation.AspNetCore;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Comanda.Profiles.WebApi.Constants;

public static class Headers
{
public const string Credential = "X-Credential";
public const string Location = "Location";
public const string Link = "Link";
public const string Pagination = "X-Pagination";
public const string Authorization = "Authorization";
public const string Idempotency = "Idempotency-Key";
public const string Correlation = "Correlation";
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static void UseHttpPipeline(this IApplicationBuilder app)
app.UseAuthentication();
app.UseAuthorization();

app.UseCorrelationMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Comanda.Profiles.WebApi.Middlewares;

public sealed class CorrelationMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
var correlationId = context.Request.Headers[Headers.Correlation].FirstOrDefault();

if (string.IsNullOrWhiteSpace(correlationId))
correlationId = context.TraceIdentifier;

context.Items[Headers.Correlation] = correlationId;
context.Response.Headers[Headers.Correlation] = correlationId;

/* enriches the logging scope with the current correlation identifier, ensuring all logs within this request pipeline share the same identifier */
/* more details: https://microsoft.github.io/code-with-engineering-playbook/observability/correlation-id/ */

using (LogContext.PushProperty(Headers.Correlation, correlationId))
using (SentrySdk.PushScope())
{
SentrySdk.ConfigureScope(scope =>
{
scope.SetTag("correlation_id", correlationId);
});

await next(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Comanda.Profiles.WebApi.Middlewares;

[ExcludeFromCodeCoverage(Justification = "contains only dependency injection")]
public static class CorrelationMiddlewareExtension
{
public static IApplicationBuilder UseCorrelationMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<CorrelationMiddleware>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

global using Comanda.Profiles.WebApi.Extensions;
global using Comanda.Profiles.WebApi.Constants;
global using Comanda.Profiles.WebApi.Middlewares;
global using Comanda.Profiles.Domain.Errors;

global using Comanda.Profiles.Application.Payloads.Traceability;
Expand All @@ -23,4 +24,5 @@

global using Scalar.AspNetCore;
global using Serilog;
global using Serilog.Context;
global using FluentValidation.AspNetCore;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ namespace Comanda.Stores.WebApi.Constants;

public static class Headers
{
public const string Authorization = "Authorization";
public const string Credential = "X-Credential";
public const string Location = "Location";
public const string Link = "Link";
public const string Pagination = "X-Pagination";
public const string Authorization = "Authorization";
public const string Idempotency = "Idempotency-Key";
public const string Correlation = "Correlation";
}
Loading
Loading