本文介绍了使用特定的HttpMessageHandler注入单实例HttpClient的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为我正在从事的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 s,然后可以通过注入 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 HttpClients 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?

任何问题,让我知道。

推荐答案

从注释添加到对话中似乎需要 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 20:07