使用特定的 HttpMessageHandler 注入单个实例 HttpClient [英] Injecting Single Instance HttpClient with specific HttpMessageHandler
问题描述
作为我正在处理的 ASP.Net Core 项目的一部分,我需要从我的 WebApi 中与许多不同的基于 Rest 的 API 端点进行通信.为了实现这一点,我使用了许多服务类,每个类都实例化一个静态 HttpClient
.基本上,我为 WebApi 连接到的每个基于 Rest 的端点都有一个服务类.
As part of an ASP.Net Core project that I am working on I have a requirement to communicate with a number of different Rest based API Endpoints from within my WebApi. To achieve this I am using a number of service classes that each instantiate a static HttpClient
. Essentially I have a service class for each of the Rest based endpoints that the WebApi connects to.
下面是如何在每个服务类中实例化静态 HttpClient
的示例.
An example of how the static HttpClient
is instantiated in each of the service classes can be seen below.
private static HttpClient _client = new HttpClient()
{
BaseAddress = new Uri("http://endpointurlexample"),
};
虽然上述方法运行良好,但它无法对使用 HttpClient
的服务类进行有效的单元测试.为了让我能够进行单元测试,我有一个假的 HttpMessageHandler
,我想在我的单元测试中用于 HttpClient
,而 HttpClient
> 已按上述方式实例化,但是我无法将伪造的 HttpMessageHandler
作为我的单元测试的一部分.
Whilst the above is working well, it does not allow for effective unit testing of the service classes that are using HttpClient
. To enable me to carry out unit testing I have a fake HttpMessageHandler
that I would like to use for the HttpClient
in my unit tests, whilst the HttpClient
is instantiated as above however I am unable to apply the fake HttpMessageHandler
as part of my unit tests.
服务类中的 HttpClient
在整个应用程序中保持单个实例的最佳方式是什么(每个端点一个实例),但允许不同的 HttpMessageHandler
在单元测试期间应用?
What is the best way for the HttpClient
in the service classes to remain a single instance throughout the application (one instance per endpoint), but to allow a different HttpMessageHandler
to be applied during the unit tests?
我想到的一种方法是不使用静态字段将 HttpClient
保存在服务类中,而是允许使用单例生命周期通过构造函数注入来注入它,这将允许我在单元测试期间使用所需的 HttpMessageHandler
指定 HttpClient
,我想到的另一个选项是使用 HttpClient
工厂类在静态字段中实例化 HttpClient
,然后可以通过将 HttpClient
工厂注入服务类来检索这些静态字段,再次允许使用相关的 HttpMessageHandler实现不同的实现代码> 在单元测试中返回.然而,以上都没有感觉特别干净,感觉必须有更好的方法吗?
One approach I have thought of would be not to use a static field to hold the HttpClient
in the service classes, rather to allow it to be injected via constructor injection using a singleton lifecycle, which would allow me to specify a HttpClient
with the desired HttpMessageHandler
during unit tests, the other option I thought of would be to use a HttpClient
Factory Class that instantiated the HttpClient
s in static fields that could then be retrieved by injecting the HttpClient
factory into the service classes, again allowing a different implementation with the relevant HttpMessageHandler
to be returned in unit tests. None of the above feel particularly clean however and it feels like there must be a better way?
有任何问题,请告诉我.
Any questions, let me know.
推荐答案
从评论中添加到对话中看起来您需要一个 HttpClient
工厂
Adding to the conversation from the comments looks like you would need a HttpClient
factory
public interface IHttpClientFactory {
HttpClient Create(string endpoint);
}
核心功能的实现可能看起来像这样.
and the implementation of the core functionality could look something like this.
public class DefaultHttpClientFactory : IHttpClientFactory, IDisposable
{
private readonly ConcurrentDictionary<string, HttpClient> _httpClients;
public DefaultHttpClientFactory()
{
this._httpClients = new ConcurrentDictionary<string, HttpClient>();
}
public HttpClient Create(string endpoint)
{
if (this._httpClients.TryGetValue(endpoint, out var client))
{
return client;
}
client = new HttpClient
{
BaseAddress = new Uri(endpoint),
};
this._httpClients.TryAdd(endpoint, client);
return client;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
foreach (var httpClient in this._httpClients)
{
httpClient.Value.Dispose();
}
}
}
也就是说,如果您对上述设计不是特别满意.您可以抽象出服务背后的 HttpClient
依赖项,这样客户端就不会成为实现细节.
That said, if you are not particularly happy with the above design. You could abstract away the HttpClient
dependency behind a service so that the client does not become an implementation detail.
服务的消费者不需要确切知道数据是如何检索的.
That consumers of the service need not know exactly how the data is retrieved.
这篇关于使用特定的 HttpMessageHandler 注入单个实例 HttpClient的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!