ASP.NET MVC中的HttpClient单例实现 [英] HttpClient Singleton Implementation in ASP.NET MVC

查看:446
本文介绍了ASP.NET MVC中的HttpClient单例实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读此博客文章和有关 www.asp.net :

HttpClient旨在实例化一次并在整个过程中重复使用 应用程序的生命周期.特别是在服务器应用程序中, 为每个请求创建一个新的HttpClient实例将耗尽 重负载下可用的插座数量.这将导致 SocketException错误.

HttpClient is intended to be instantiated once and re-used throughout the life of an application. Especially in server applications, creating a new HttpClient instance for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors.

我发现我们的代码在每次调用时都处理了HttpClient.我正在更新代码,以便我们可以重用HttClient,但我担心的是我们的实现,但不是线程安全的.

I discovered that our code was disposing the HttpClient on each call. I'm updating our code so that we reuse the HttClient, but I'm concerned our implement but not thread-safe.

这是新代码的当前草案:

Here is the current draft of new code:

对于单元测试,我们为HttpClient实现了一个包装器,使用者将其称为包装器:

For Unit Testing, we implemented an wrapper for HttpClient, the consumers call the wrapper:

 public class HttpClientWrapper : IHttpClient
    {
        private readonly HttpClient _client;

        public Uri BaseAddress
        {
            get
            {
                return _client.BaseAddress;
            }

            set
            {
                _client.BaseAddress = value;
            }
        }

        public HttpRequestHeaders DefaultRequestHeaders
        {
            get
            {
                return _client.DefaultRequestHeaders;
            }
        }

        public HttpClientWrapper()
        {
            _client = new HttpClient();
        }

        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, String userOrProcessName)
        {
            IUnityContainer container = UnityCommon.GetContainer();
            ILogService logService = container.Resolve<ILogService>();

            logService.Log(ApplicationLogTypes.Debug, JsonConvert.SerializeObject(request), userOrProcessName);

            return _client.SendAsync(request);
        }

        #region IDisposable Support
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing && _client != null)
                {
                    _client.Dispose();
                }

                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
    } 

以下是一项服务,该服务会调用:

Here is a service that calls:

public class EnterpriseApiService : IEnterpriseApiService
    {
        private static IHttpClient _client;

        static EnterpriseApiService()
        {
            IUnityContainer container = UnityCommon.GetContainer();
            IApplicationSettingService appSettingService = container.Resolve<IApplicationSettingService>();

            _client = container.Resolve<IHttpClient>();
        }

        public EnterpriseApiService() { }

        public Task<HttpResponseMessage> CallApiAsync(Uri uri, HttpMethod method, HttpContent content, HttpRequestHeaders requestHeaders, bool addJsonMimeAccept = true)
        {
            IUnityContainer container = UnityCommon.GetContainer();
            HttpRequestMessage request;

           _client.BaseAddress = new Uri(uri.GetLeftPart(UriPartial.Authority));

            if (addJsonMimeAccept)
                _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            request = new HttpRequestMessage(method, uri.AbsoluteUri);

            // Removed logic that built request with content, requestHeaders and method

            return _client.SendAsync(request, UserOrProcessName);
        }
    }

我的问题:

  1. 这是重用HttpClient对象的合适方法吗?
  2. 是否为EnterpriseApiService的所有实例共享了静态_httpClient字段(由静态构造函数填充)?我想确认一下,因为实例方法正在调用它.
  3. 调用CallApiAsync()时,如果对静态HttpClient进行了更改,例如"_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")),则这些值可能会被另一个进程覆盖在最后一行"_client.SendAsync"之前被调用?我担心在处理CallApiAsync()的过程中会更新静态实例.
  4. 由于它正在调用SendAsync(),我们是否可以确保将响应映射回正确的调用者?我想确认响应没有传给其他呼叫者.

更新: 由于删除了USING语句,并且Garage Collection不调用Dispose,因此我将采用在该方法中创建新实例的更安全方法.即使在线程生命周期内也要重用HttpClient实例,这将需要对逻辑进行大量修改,因为该方法会在每次调用时设置HttpClient属性.

Update: Since I've removed the USING statements, and the Garage Collection doesn't call Dispose, I'm going to go with the safer approach of creating a new instance within the method. To reuse an instance of HttpClient even within the thread lifetime, it would require a significant reworking of the logic because the method sets HttpClient properties per call.

推荐答案

您真的要一个实例吗?

我认为您不希望在整个应用程序范围内使用一个实例.每个线程需要一个实例.否则,您将不会获得很好的性能!而且,这将解决您的问题#3和#4,因为没有两个线程将同时访问同一HttpClient.

Do you really want one instance?

I don't think you want one instance application-wide. You want one instance per thread. Otherwise you won't get very good performance! Also, this will resolve your questions #3 and #4, since no two threads will be accessing the same HttpClient at the same time.

只需使用 Container.Resolve PerThreadLifetimeManager .

这篇关于ASP.NET MVC中的HttpClient单例实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆