August 10 2024
Sponsored
• Transform your API development process with Postman Flows! Experience a new way to visually create, debug, and automate complex API workflows with ease. Dive into the future of API management and enhance your productivity here.
Many thanks to the sponsors who make it possible for this newsletter to be free for readers. Become a sponsor.
In C#/.NET, a DelegatingHandler is a special type of message handler that is part of the HTTP client pipeline used to process HTTP requests and responses. It is a class that derives from HttpMessageHandler and is used to intercept and modify HTTP messages as they flow in and out of an HttpClient.
DelegatingHandler works by wrapping around another HttpMessageHandler.
When you send a request using HttpClient, the request travels through a chain of handlers, each possibly modifying the request or generating a response.
Eventually, the request reaches the innermost handler, typically the HttpClientHandler, which sends the request over the network.
This feature is particularly useful for tasks like logging, authentication, and other cross-cutting concerns.
Today I'm going to show how to implement it with authentication.
var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpClient<NewsletterService>(httpClient =>{ httpClient.BaseAddress = new Uri("https://api.newsletter.com");}); var app = builder.Build(); app.Run();
What did we do here?
We have created Typed HttpClient - NewsletterService.
And we set BaseAddress to point to our API endpoint.
The NewsletterService is a class that will have 2 methods:
public class NewsletterService(HttpClient client){ public async Task<NewsletterUser?> GeEmailByIdAsync(string id) { var endpoint = $"users/{id}"; return await client.GetFromJsonAsync<NewsletterUser>(endpoint); } public async Task<double> GetOpenRateAsync(string id) { var endpoint = $"issues/{id}/open-rate"; return await client.GetFromJsonAsync<double>(endpoint); }}
All set.
When we call any of these 2 methods, we get 401 Unauthorized.
Why?
Because the API we're targeting requires a passed AccessToken in order to access it.
Okay, nothing difficult, right?
We will add to both methods the Authorization RequestHeader with the AccessToken.
No no. Today we will show a better way.
That's right, using a DelegatingHandler.
public class AuthenticationDelegatingHandler : DelegatingHandler{ protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { //Don't hardcode those values request.Headers.Add("Authorization", "secretAccessToken"); request.Headers.Add("SomeOtherHeader", "someOtherValue"); return base.SendAsync(request, cancellationToken); }}
What have we achieved with this?
We gave the command:
"Before you send the HttpClient request, enrich it with these headers that I am passing on to you".
And yes, this applies to every request associated with the NewsletterService.
How?
So let's not forget to tell HttpClient to use the Handler we created.
We will do it in the following way:
builder.Services.AddTransient<AuthenticationDelegatingHandler>(); builder.Services.AddHttpClient<NewsletterService>(httpClient =>{ httpClient.BaseAddress = new Uri("https://api.newsletter.com");})
Today we have shown the most efficient way to solve Authentication with HttpClient. We used TypedClient and DelegateHandler.
DelegatingHandler is especially powerful in scenarios where you need to apply consistent modifications or checks to requests/responses in a clean and reusable way.
For example, in a microservices architecture, you might use several handlers to handle concerns like logging, error handling, and retry policies before a request reaches an external service or database.
This design promotes separation of concerns and reusability across different parts of your application or across different applications within an organization.
Try to use the same approach to handle some other stuff like we did authentication today. That's all from me today.
Stop arguing about code style. In this course you get a production-proven setup with analyzers, CI quality gates, and architecture tests — the exact system I use in real projects. Join here.
Not sure yet? Grab the free Starter Kit — a drop-in setup with the essentials from Module 01.
Design Patterns that Deliver — Solve real problems with 5 battle-tested patterns (Builder, Decorator, Strategy, Adapter, Mediator) using practical, real-world examples. Trusted by 650+ developers.
Just getting started? Design Patterns Simplified covers 10 essential patterns in a beginner-friendly, 30-page guide for just $9.95.
Every Monday morning, I share 1 actionable tip on C#, .NET & Architecture that you can use right away. Join here.
Join 20,000+ subscribers who mass-improve their .NET skills with actionable tips on C#, Architecture & Best Practices.
Subscribe to the TheCodeMan.net and be among the 20,000+ subscribers gaining practical tips and resources to enhance your .NET expertise.