应该使用哪种类型的单例模式为我的Web应用程序创建HTTP客户端

时间:2015-11-10 12:59:15

标签: asp.net asp.net-mvc-4 singleton httpclient web-optimization

我有一个网络应用程序。我发现性能瓶颈可能是我为每个请求一次又一次地创建Http客户端。

public static class DemoHttpClient
    {
       public static HttpClient GetClient()
       {
           HttpClient client = new HttpClient();
           client.BaseAddress = new Uri(DemoConstants.DemoAPI);
           client.DefaultRequestHeaders.Accept.Clear();
           client.DefaultRequestHeaders.Accept.Add(
                new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

           return client;
}
    }

public class DemoConstants
{
    public const string DemoAPI = "http://localhost/";
}

我打算为此实施单身人士。并找到了这篇非常有用的文章。 http://csharpindepth.com/Articles/General/Singleton.aspx

我很困惑ASP.NET MVC Web应用程序生命周期在服务器上部署时的确切程度。假设将有多个线程调用相同的资源,资源会一次又一次地创建新的http客户端..

我们应该在这做什么.. 1)懒惰加载HTTP客户端? 2)不懒惰加载吗?

我们应该使用哪种特殊方法?

1 个答案:

答案 0 :(得分:0)

这听起来不是一个好主意。特别要看一下HttpClient类的文档:

  

此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。

https://msdn.microsoft.com/en-us/library/system.net.http.httpclient%28v=vs.118%29.aspx

这意味着从多个线程访问完全相同的单例实例将导致未定义的问题。

>您可以在单个请求中重复使用相同的实例。这可以通过在Items容器中存储实例来完成:

   private static string ITEMSKEY = "____hclient";

   public static HttpClient GetClient()
   {
       if ( HttpContext.Current.Items[ITEMSKEY] == null )
       {
          HttpClient client = new HttpClient();
          client.BaseAddress = new Uri(DemoConstants.DemoAPI);
          client.DefaultRequestHeaders.Accept.Clear();
          client.DefaultRequestHeaders.Accept.Add(
            new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

          HttpContext.Current.Items.Add( ITEMSKEY, client );
       }

       return (HttpClient)HttpContext.Current.Items[ITEMSKEY];
    }

请注意,由于HttpClient实现了IDisposable,因此在管道中的某个位置处置此类实例仍然是个好主意,例如在应用程序管道的EndRequest事件中

更新:正如@LukeH的评论中所述,.NET 4.5和4.6文档的更新版本指出HttpClient类的某些方法 线程安全:

https://msdn.microsoft.com/en-us/library/system.net.http.httpclient%28v=vs.110%29.aspx

更新后的备注部分指出,单个实例基本上是应用于此实例执行的所有请求的共享设置的集合。然后,文档说:

  

此外,每个HttpClient实例都使用自己的连接池,将其请求与其他HttpClient实例执行的请求隔离开来。

这意味着不同池的隔离仍然有意义,我的个人建议仍然是不要单独使用,因为您可能仍需要在连续请求之间更改某些设置。