作为我正在处理的 ASP.Net Core 项目的一部分,我需要从我的 WebApi 中与许多不同的基于 Rest 的 API 端点进行通信。为了实现这一点,我使用了许多服务类,每个服务类都实例化一个静态 HttpClient
.本质上,我为 WebApi 连接到的每个基于 Rest 的端点都有一个服务类。
如何静态的例子HttpClient
在每个服务类中实例化如下所示。
private static HttpClient _client = new HttpClient()
{
BaseAddress = new Uri("http://endpointurlexample"),
};
虽然上面的方法运行良好,但它不允许对使用 HttpClient
的服务类进行有效的单元测试。 .为了使我能够进行单元测试,我有一个假的 HttpMessageHandler
我想用于 HttpClient
在我的单元测试中,同时 HttpClient
如上所述实例化但是我无法应用假 HttpMessageHandler
作为我的单元测试的一部分。
HttpClient
的最佳方式是什么?在服务类中在整个应用程序中保持单个实例(每个端点一个实例),但允许不同的 HttpMessageHandler
在单元测试期间应用?
我想到的一种方法是不使用静态字段来保存 HttpClient
在服务类中,而不是允许它使用单例生命周期通过构造函数注入(inject)来注入(inject),这将允许我指定一个 HttpClient
与所需的 HttpMessageHandler
在单元测试期间,我想到的另一个选择是使用 HttpClient
实例化 HttpClient
的工厂类s 在静态字段中,然后可以通过注入(inject) HttpClient
来检索工厂进入服务类,再次允许与相关的不同实现 HttpMessageHandler
在单元测试中返回。但是,以上都不是特别干净,感觉必须有更好的方法?
有任何问题,请告诉我。
最佳答案
添加到评论中的对话看起来您需要一个 HttpClient
工厂
public interface IHttpClientFactory {
HttpClient Create(string endpoint);
}
核心功能的实现可能看起来像这样。
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
依赖性,这样客户端就不会成为实现细节。
服务的消费者不需要确切地知道数据是如何检索的。
关于c# - 使用特定的 HttpMessageHandler 注入(inject)单实例 HttpClient,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43118874/