Lor*_*eno 8 .net c# dependency-injection .net-core
我正在构建一个 API 客户端。我的 API 相当大,所以我决定将其分成大约 5 个(私有)子客户端,每个子客户端涵盖 API 的不同部分。5 个客户端使用起来不太舒服,所以我希望将它们置于 1 (public) 之下ApiClient,这将充当这 5 个客户端之上的一种外观。问题是我可能应该HttpClient在所有这些子客户端之间共享一个。据我所知,我可以做这样的事情:
services.AddHttpClient<SubClient1>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
Run Code Online (Sandbox Code Playgroud)
通过上面的行,我的SubClient1将被注入到我的公共中ApiClient,并且HttpClient已经使用BaseAddress. 现在,我如何注册所有 5 个子客户端(SubClient1、SubClient2、SubClient3、 ...)以便他们每个人都收到相同的信息HttpClient?我认为下面的代码将创建 5 个HttpClient实例:
services.AddHttpClient<SubClient1>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient2>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient3>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient4>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient5>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
Run Code Online (Sandbox Code Playgroud)
我该如何解决这个问题?
我不同意@Athanasios Kataras 的回答。但我不明白为什么你需要将其变成单例。
基本上有 3 种方法可以将 http 客户端依赖注入到服务中;直接、键入和命名。@Athanasios 所做的是直接的。但在这种情况下,我相信命名的 HttpClient 是正确的选择。但是您也可以只使用注入到子客户端中的类型,假设客户端的行为在所有子客户端中都是相同的。
public class Startup
{
private IConfiguration Configuration { get; }
private IHostEnvironment HostEnvironment { get; set; }
public Startup(IConfiguration configuration, IHostEnvironment env)
{
Configuration = configuration;
HostEnvironment = env;
}
public void ConfigureServices(IServiceCollection services)
{
//Named client
services.AddHttpClient("myapi", c =>
{
c.BaseAddress = new System.Uri("https://myapi.com");
});
//Typed client
services.AddHttpClient<iMyApi, MyApi>(c =>
c.BaseAddress = new System.Uri("https://myapi.com");
});
}
}
Run Code Online (Sandbox Code Playgroud)
这会将 HttpClient 添加到 HttpClientFactory,您现在可以在任何项目中使用它。
public class SubClient
{
private readonly IHttpClientFactory httpFactory;
private readonly HttpClient namedClient;
private readonly iMyApi typedClient;
private readonly static string clientName = "myapi";
public SubClient(IHttpClientFactory httpClientFactory, iMyApi myApiClient)
{
this.namedClient = httpClientFactory.Create(clientName);
this.typedClient = myApiClient;
}
}
Run Code Online (Sandbox Code Playgroud)
对于类型化客户端,它取决于您创建一个实现 api 端点的实现。这样做的优点是您拥有一个可在任何服务中使用的临时客户端。并且您可以将自己从我怀疑的大量重复代码中解放出来。
您正在使用HttpClientFactory,因此将 的构建委托HttpClient给工厂。
如前面的代码所示注册客户端服务,使 DefaultClientFactory 为每个服务创建一个标准 HttpClient。
它是有意这样做的,以便您可以根据服务配置客户端。
就资源而言,你被转换了。这就是客户工厂的最初目的:
每次从 IHttpClientFactory 获取 HttpClient 对象时,都会返回一个新实例。但每个 HttpClient 都使用由 IHttpClientFactory 池化和重用的 HttpMessageHandler,以减少资源消耗,只要 HttpMessageHandler 的生命周期尚未过期。
处理程序池是可取的,因为每个处理程序通常管理其自己的底层 HTTP 连接;创建过多的处理程序可能会导致连接延迟。某些处理程序还无限期地保持连接打开,这可能会阻止处理程序对 DNS 更改做出反应。
如果您不想使用推荐的工厂方式,您可以执行以下操作:https: //nodogmablog.bryanhogan.net/2017/10/reusing-httpclient-with-dependency-injection/
public void ConfigureServices(IServiceCollection services)
{
Uri endPointA = new Uri("http://localhost:58919/"); // this is the endpoint HttpClient will hit
HttpClient httpClient = new HttpClient()
{
BaseAddress = endPointA,
};
ServicePointManager.FindServicePoint(endPointA).ConnectionLeaseTimeout = 60000; // sixty seconds
services.AddSingleton<HttpClient>(httpClient); // note the singleton
services.AddMvc();
}
Run Code Online (Sandbox Code Playgroud)