问题描述
public class MyHandler : DelegatingHandler
{
private readonly HttpClient _httpClient;
private readonly MyHandlerOptions _config;
public MyHandler(
HttpClient httpClient,IOptions<MyHandlerOptions> options)
{
_httpClient = httpClient;
_config = options.Value;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
{
request.Headers.Authorization = await GetAccesstoken()
return await base.SendAsync(request,cancellationToken);
}
private async Task<string> GetAccesstoken()
{
//some logic to get access token using _httpClient and _config
}
}
它需要配置对象MyHandlerOptions
。它的形式在这里不是很重要。它基本上包含clientId,clientSecret等,这些是处理程序知道如何获取访问令牌所需的。
我有一些服务(类型为http客户端)需要使用MyHandler
:
//registration of MyHandler itself
builder.Services.AddHttpClient<MyHandler>();
//configuration of MyHandler
builder.Services.AddOptions<MyHandlerOptions>()
.Configure<IConfiguration>((config,configuration) =>
{
configuration.GetSection("MyHandlerOptions").Bind(config);
});
//Services that need to use MyHandler:
services.AddHttpClient<Service1>()
.AddHttpMessageHandler<MyHandler>();
services.AddHttpClient<Service2>()
.AddHttpMessageHandler<MyHandler>();
services.AddHttpClient<Service3>()
.AddHttpMessageHandler<MyHandler>();
问题是我注册的MyHandlerOptions
实例仅在与Service1
一起使用时才有效。但是,Service2
和Service3
需要其他配置(不同的clientId,clientSecret等)。我该如何实现?
我想到的可能的解决方案:
- 创建新服务:
public class AccesstokenGetter
{
Task<string> GetAccesstoken(AccesstokenConfig config)
{
//get the access token...
}
}
- 针对每种配置不同的情况分别创建
HttpMessageHandler
:
public class MyHandler1 : DelegatingHandler
{
private readonly MyHandler1Options _config;
private readonly AccesstokenGetter _accesstokenGetter;
public MyHandler(AccesstokenGetter accesstokenGetter,IOptions<MyHandlerOptions1> options)
{
_accesstokenGetter = accesstokenGetter;
_config = options.Value;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
{
//somehow convert _config to AccesstokenConfig
request.Headers.Authorization = await _accesstokenGetter.GetAccesstoken(_config)
return await base.SendAsync(request,cancellationToken);
}
}
public class MyHandler2 : DelegatingHandler
{
//same implementation as MyHandler1,just use MyHandler2Options instead
}
- 注册我的服务:
//configurations
builder.Services.AddOptions<MyHandler1Options>()
.Configure<IConfiguration>((config,configuration) =>
{
configuration.GetSection("MyHandler1Options").Bind(config);
});
builder.Services.AddOptions<MyHandler2Options>()
.Configure<IConfiguration>((config,configuration) =>
{
configuration.GetSection("MyHandler2Options").Bind(config);
});
//AccesstokenGetter
services.AddHttpClient<AccesstokenGetter>()
//Services that need to use MyHandlers:
services.AddHttpClient<Service1>()
.AddHttpMessageHandler<MyHandler1>();
services.AddHttpClient<Service2>()
.AddHttpMessageHandler<MyHandler2>();
services.AddHttpClient<Service3>()
.AddHttpMessageHandler<MyHandler2>();
有更好的解决方案吗?我不是这个想法的忠实拥护者,也不是很灵活。
解决方法
services.AddHttpClient<Service1>()
.AddHttpMessageHandler(sp =>
{
var handler = sp.GetRequiredService<MyHandler>();
handler.Foo = "Bar";
return handler;
});
services.AddHttpClient<Service2>()
.AddHttpMessageHandler(sp =>
{
var handler = sp.GetRequiredService<MyHandler>();
handler.Foo = "Baz";
return handler;
});