如何确保在C#中仅将HttpClient初始化一次?

时间:2019-09-05 10:47:56

标签: c# concurrency dotnet-httpclient

根据Microsoft的指南,我想通过仅拥有HttpClient公关的一个实例来确保正确使用HttpClient。 API已消耗。我对我的解决方案正常工作感到有些疲倦

我尝试在创建函数周围添加锁,如果静态变量为null,则会调用该函数。

    public class BaseClient
    {
        private static volatile HttpClient _httpClient;
        private static readonly object HttpClientLock = new object();

        public BaseClient(string serviceAddress, string apiKeyRequestHeader, string apiKeyValue)
        {
            CreateClient(serviceAddress, apiKeyValue, apiKeyRequestHeader);
        }

        private void CreateClient(string baseAddress, string apiKeyRequestHeaderValue, string apiKeyRequestHeader)
        {
            if (_httpClient == null)
            {
                lock (HttpClientLock)
                {
                    if (_httpClient == null)
                    {
                        _httpClient = new HttpClient
                        {
                            BaseAddress = new Uri(baseAddress)
                        };

                        _httpClient.DefaultRequestHeaders.Accept.Add(
                            MediaTypeWithQualityHeaderValue.Parse("application/json"));
                        if (!string.IsNullOrEmpty(apiKeyRequestHeaderValue))
                            _httpClient.DefaultRequestHeaders.Add(apiKeyRequestHeader, apiKeyRequestHeaderValue);
                        _httpClient.Timeout = new TimeSpan(0, 3, 0);
                    }
                }
            }
        }
    }

我想确保HttpClient对于每个类都只实例化一次,因此在使用套接字时不会溢出。这段代码可以保证发生这种情况吗?

1 个答案:

答案 0 :(得分:3)

确保HttpClient只有一个实例的最简单方法是利用静态初始化(默认情况下是线程安全的)(由框架保证),该静态初始化在post中有关于C#中可能的单例实现。

在此示例之后,您可以通过避免锁定来简化代码:

public class BaseClient
{
    private static readonly HttpClient _httpClient = new HttpClient();

    static BaseClient()
    {
    }

    public BaseClient(string serviceAddress, string apiKeyRequestHeader, string apiKeyValue)
    {
        InitializeClient(serviceAddress, apiKeyValue, apiKeyRequestHeader);
    }

    private void InitializeClient(string baseAddress, string apiKeyRequestHeaderValue, string apiKeyRequestHeader)
    {
        _httpClient.BaseAddress = new Uri(baseAddress);
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        _httpClient.Timeout = TimeSpan.FromMinutes(3);

        if (!string.IsNullOrEmpty(apiKeyRequestHeaderValue))
        {
            _httpClient.DefaultRequestHeaders.Add(apiKeyRequestHeader, apiKeyRequestHeaderValue);
        }
    }
}

除此之外,您始终可以测试方法并检查一次是否可以有多个实例。

注意: 当DNS changes时,拥有一个HttpClient实例可能会导致问题。如果您使用的是.Net Core,则应改用HttpClientFactory,因为Microsoft在那里对问题进行了排序。