Chain of Responsibility in ASP.NET Core: middleware pipeline and HttpClient DelegatingHandler

.NET Architecture & Design Patterns November 13, 2026 csharp

The middleware pipeline: each middleware does something, then calls next or stops the chain (short-circuit).

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// ======================================================================
// Q: Where is Chain of Responsibility in ASP.NET Core?
//
// The middleware pipeline: each middleware does something, then calls next or
// stops the chain (short-circuit). The same applies to DelegatingHandler in
// HttpClient.
// ======================================================================

app.UseExceptionHandler();      // order matters: first so it catches everything
app.UseAuthentication();        // before Authorization
app.UseAuthorization();

app.Use(async (ctx, next) =>    // custom middleware
{
    var sw = Stopwatch.StartNew();
    await next(ctx);            // the next link in the chain
    app.Logger.LogInformation("{Path} took {Ms} ms", ctx.Request.Path, sw.ElapsedMilliseconds);
});

// Outgoing: chain in HttpClient
public class CorrelationIdHandler(IHttpContextAccessor accessor) : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage req, CancellationToken ct)
    {
        req.Headers.TryAddWithoutValidation("X-Correlation-Id", accessor.HttpContext?.TraceIdentifier);
        return base.SendAsync(req, ct);
    }
}
builder.Services.AddTransient<CorrelationIdHandler>();
builder.Services.AddHttpClient<IErpClient, ErpClient>().AddHttpMessageHandler<CorrelationIdHandler>();