【发布时间】:2021-02-05 20:01:09
【问题描述】:
根据 Microsoft 文档中的最佳实践,我正在使用 AddHttpClient 注入一个 HttpClient(使用 Typed clients),但这种方法不允许我配置我的服务的其余依赖项。
假设我有这个设置:
public interface ISerializer { /*...*/ }
public class Serializer : ISerializer {
private readonly string _options;
public Serializer(string options)
{
_options = options;
}
/*...*/
}
public class ServiceA
{
private readonly HttpClient _client;
private readonly ISerializer _serializer;
public ServiceA(HttpClient httpClient, ISerializer serializer)
{
_client = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
}
public string MakeCall()
{
// var body = _serializer.Serialize();
return _client.GetAsync("").Result.StatusCode.ToString();
}
}
public class ServiceB {
/*
Similar to ServiceA
*/
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddServiceAandB(this IServiceCollection services)
{
/*
If I do this below, Serializer("option 1") will be used in Services A and B
however, what I would like is to have different Serializer's configurations for A and B (see full question below)
*/
services.AddTransient<ISerializer>((p) => new Serializer("option 1"));
services.AddHttpClient<ServiceA>(c =>
{
c.BaseAddress = new Uri("api-url-for-A");
c.Timeout = TimeSpan.FromSeconds(5);
});
services.AddHttpClient<ServiceB>(c =>
{
c.BaseAddress = new Uri("api-url-for-B");
c.Timeout = TimeSpan.FromSeconds(5);
});
return services;
}
}
问题:如何使用 Serializer("option 1") 为 ServiceA 和 Serializer("option 2") 为 ServiceB 配置 ISerializer 依赖关系?但是,因为我使用的是 AddHttpClient 并且它自己负责构建 ServiceA 和 ServiceB,所以我无法按照我的意愿进行配置。
注意:正如建议的那样,创建多个实现可能适用于简单的情况,但想象一下 Serializer 接收一个 Options 对象,并且为所有选项组合创建不同的实现是不可能的。这就是我想在 DI 设置期间配置选项的原因。
任何帮助将不胜感激。
-------- 更新 1 --------
我不打算注入两个 ISerializer,而是能够配置 Serializer 并在构造 ServiceA 和 ServiceB 的同时利用 .AddHttpClient。
例如(下面的代码是不可能的,但很理想):
services.AddHttpClient<ServiceA>(c =>
{
c.BaseAddress = new Uri("api-url-for-A");
c.Timeout = TimeSpan.FromSeconds(5);
});
services.AddTransient<ServiceA>(p => {
return new ServiceA(p.GetHttpClientFor<ServiceA>(), new Serializer("option 1"));
});
services.AddHttpClient<ServiceB>(c =>
{
c.BaseAddress = new Uri("api-url-for-B");
c.Timeout = TimeSpan.FromSeconds(5);
});
services.AddTransient<ServiceB>(p => {
return new ServiceB(p.GetHttpClientFor<ServiceB>(), new Serializer("option 2"));
});
// neither IServiceProvider.GetHttpClient method exists, nor I can use .AddHttpClient with AddTransient for same dependency.
【问题讨论】:
-
为
ISerializer引入不同的实现类型,让不同的服务可以使用不同的选项。 -
这行不通。您不能向管道中注入多个
ISerializer。否则框架如何知道将哪个注入到需要它的服务中。 -
@Fabio 我的例子就是一个例子,但想象一下 Serializer 接收不同的序列化选项(缩进、不缩进、使用驼峰式大小写、使用偷偷摸摸的大小写),创建多个实现将是致命的。
-
@Andy,我添加了更新 1 以澄清您的观点。
标签: c# asp.net-core .net-core dependency-injection dotnet-httpclient