应该使用哪种类型的单例模式来为我的 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.
这意味着不同池的隔离仍然有意义,我个人的建议仍然是不要有单例,因为您可能仍然需要在连续请求之间更改一些设置。
我有一个网络应用程序。我发现性能瓶颈可能是我为每个请求一次又一次地创建 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.
这意味着不同池的隔离仍然有意义,我个人的建议仍然是不要有单例,因为您可能仍然需要在连续请求之间更改一些设置。