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

Which type of singleton pattern should be used for creating HTTP client for my web application

我有一个网络应用程序。我发现性能瓶颈可能是我为每个请求一次又一次地创建 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) 不是懒加载吗?

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

这听起来不是个好主意。特别是,查看 HttpClient class:

的文档

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

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 事件中应用程序管道。

Update:如@LukeH 的评论所述,.NET 4.5 和 4.6 文档的更新版本指出 HttpClient class 线程安全的:

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

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

In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.

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