AugusteVN.HttpClient.Delegator
1.0.3
dotnet add package AugusteVN.HttpClient.Delegator --version 1.0.3
NuGet\Install-Package AugusteVN.HttpClient.Delegator -Version 1.0.3
<PackageReference Include="AugusteVN.HttpClient.Delegator" Version="1.0.3" />
paket add AugusteVN.HttpClient.Delegator --version 1.0.3
#r "nuget: AugusteVN.HttpClient.Delegator, 1.0.3"
// Install AugusteVN.HttpClient.Delegator as a Cake Addin #addin nuget:?package=AugusteVN.HttpClient.Delegator&version=1.0.3 // Install AugusteVN.HttpClient.Delegator as a Cake Tool #tool nuget:?package=AugusteVN.HttpClient.Delegator&version=1.0.3
Delegating Handler
Adds a custom HttpClient message handler / delegating handler that can add headers to the request. The delegator gets those values from a keyed singleton. And registers a resolver for that keyed singleton.
This way, any caller of that HttpClient can access or alter those header values on the 'shared' singleton.
It holds a Local
and a Global
set of those headers. The local values are only applicable to the HttpClient you added the delegator to.
The global values are applied on all HttpClients. Local values can override global values, not the other way around.
The interface of the resolver 'IHttpClientFactory<T>' implements the original 'IHttpClientFactory', hides its methods but uses those under the hood.
So, you can use the .CreateClient
but also have the singleton values available by just one dependency injection instead of two.
It contains what was covered in this video: Authorize HttpClient with Delegating Handler C# .NET
Sandbox, work in progress
builder.Services.AddHttpClient(nameof(TUtils), client => client.BaseAddress = new Uri("https://localhost:3000"))
.AddDelegator<TUtils>();
builder.Services.AddHttpClient(nameof(TPetService), client => client.BaseAddress = new Uri("https://localhost:3005"))
.AddDelegator<TPetService>();
builder.Services.AddHttpClientStateResolver<NewsletterSubscribersHttpClient>(nameof(TUtils));
builder.Services.AddScoped<AuthService>();
builder.Services.AddScoped<PetService>();
builder.Services.AddScoped<NewsletterSubscribersHttpClient>();
var app = builder.Build();
app.MapGet("/", (AuthService auth, NewsletterSubscribersHttpClient news, PetService pet) =>
{
auth.AuthorizeClient("<access-token>");
auth.PrintLocalState(); // AuthService Local: client name: [TUtils], headers: [[x-news, bar]]
auth.PrintGlobalState(); // AuthService Global: client names: [TPetService,TUtils], headers: [[x-bar, foo],[Authorization, Bearer <access-token>]]
news.PrintLocalState(); // Newsletter Local: client name: [TUtils], headers: [[x-news, bar]]
news.PrintGlobalState(); // Newsletter Global: client names: [TPetService,TUtils], headers: [[x-bar, foo],[Authorization, Bearer <access-token>]]
pet.PrintLocalState(); // PetService Local: client name: [TPetService], headers: [[x-pet-service, foo]]
pet.PrintGlobalState(); // PetService Global: client names: [TPetService,TUtils], headers: [[x-bar, foo],[Authorization, Bearer <access-token>]]
Results.Ok();
});
app.Run();
public record TUtils;
public record TPetService;
public class AuthService
{
private readonly HttpClient _httpClient;
private readonly IHttpClientFactory<TUtils> _httpState;
public AuthService(IHttpClientFactory<TUtils> httpState)
{
_httpClient = httpState.CreateClient();
_httpState = httpState;
}
public void AuthorizeClient(string? token)
{
_httpState.Global.AddHeader("Authorization", $"Bearer {token}");
}
public void PrintLocalState()
{
Console.WriteLine($"AuthService Local: client name: [{_httpState.Local.ClientName}], headers: [{string.Join(',', _httpState.Local.Headers)}]");
}
public void PrintGlobalState()
{
Console.WriteLine($"AuthService Global: client names: [{string.Join(',', _httpState.Global.ClientNames)}], headers: [{string.Join(',', _httpState.Global.Headers)}]");
}
}
public class PetService
{
private readonly HttpClient _httpClient;
private readonly IHttpClientFactory<TPetService> _httpState;
public PetService(IHttpClientFactory<TPetService> httpState)
{
_httpClient = httpState.CreateClient();
_httpState = httpState;
_httpState.Local.AddHeader("x-pet-service", "foo");
}
public void PrintLocalState()
{
Console.WriteLine($"PetService Local: client name: [{_httpState.Local.ClientName}], headers: [{string.Join(',', _httpState.Local.Headers)}]");
}
public void PrintGlobalState()
{
Console.WriteLine($"PetService Global: client names: [{string.Join(',', _httpState.Global.ClientNames)}], headers: [{string.Join(',', _httpState.Global.Headers)}]");
}
}
public class NewsletterSubscribersHttpClient
{
private readonly HttpClient _httpClient;
private readonly IHttpClientFactory<NewsletterSubscribersHttpClient> _httpState;
public NewsletterSubscribersHttpClient(IHttpClientFactory<NewsletterSubscribersHttpClient> httpState)
{
_httpClient = httpState.CreateClient();
_httpState = httpState;
_httpState.Local.AddHeader("x-news", "bar");
_httpState.Global.AddHeader("x-bar", "foo");
}
public void PrintLocalState()
{
Console.WriteLine($"Newsletter Local: client name: [{_httpState.Local.ClientName}], headers: [{string.Join(',', _httpState.Local.Headers)}]");
}
public void PrintGlobalState()
{
Console.WriteLine($"Newsletter Global: client names: [{string.Join(',', _httpState.Global.ClientNames)}], headers: [{string.Join(',', _httpState.Global.Headers)}]");
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Update README.