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



我有一个web应用程序。我发现性能瓶颈可能是我为每个请求一次又一次地创建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/";
}

我正计划为此实施singleton。我发现这篇文章很有帮助。http://csharpindepth.com/Articles/General/Singleton.aspx

当ASP.NET MVC web应用程序部署在服务器上时,我对它的生命周期究竟是如何的感到困惑。假设将有多个线程调用同一资源,则该资源会一次又一次地生成新的http客户端。。

我们在这里该怎么办。。1) 懒惰地加载HTTP客户端?2) 不是懒洋洋地装?

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

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

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

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

这意味着从多个线程访问同一个singleton实例将导致未定义的问题。

然而,可以做的是,可以在单个请求中重用同一个实例。这可以通过在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实例执行的请求隔离开来。

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

最新更新