C# 单例httpclient与创建新的httpclient请求
我正在尝试在我的C# 单例httpclient与创建新的httpclient请求,c#,xamarin,design-patterns,httpclient,C#,Xamarin,Design Patterns,Httpclient,我正在尝试在我的Xamarin.Formsmobile应用程序中使用HttpClient为webservice创建层 无singlton模式 单件模式 在第一种方法中,我在每个新请求中创建新的http客户机对象 通过移动应用程序 这是我的密码 public HttpClient GetConnection() { HttpClient httpClient = new HttpClient(); httpClient.Base
Xamarin.Forms
mobile应用程序中使用HttpClient为webservice创建层
public HttpClient GetConnection()
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(baseAddress);
httpClient.Timeout = System.TimeSpan.FromMilliseconds(timeout);
return httpClient;
}
邮政编码
public async Task<TResult> PostAsync<TRequest, TResult>(String url, TRequest requestData)
{
HttpClient client = GetConnection();
String responseData = null;
if (client != null)
{
String serializedObject = await Task.Run(() => JsonConvert.SerializeObject(requestData, _jsonSerializerSettings));
var jsonContent = new StringContent(serializedObject, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(new Uri(url, UriKind.Relative), jsonContent);
responseData = await HandleResponse(response);
return await Task.Run(() => JsonConvert.DeserializeObject<TResult>(responseData, _jsonSerializerSettings));
}
else
{
throw new NullReferenceException("NullReferenceException @ PostAsync httpclient is null WebRequest.cs");
}
}
public Task<HttpResponseMessage> sendData(String url,String jsonData)
{
var jsonContent = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
return getConnection().PostAsync(new Uri(url, UriKind.Relative), jsonContent);
}
实现IWebRequest
_webRequest.PostAsync<UserRequest,bool>(Constants.USER_LOGIN, userRequest);
我在web上浏览了许多库,如
RestSharp
,只是为了探索最好的库,我发现大多数库都是根据请求创建新对象的。因此,我不知道哪种模式最适合。更新:似乎使用单一的HttpClient
静态实例,因此解决方案是使用HttpClientFactory
。有关Microsoft文档,请参阅
要使用HttpClientFactory
,您必须使用Microsoft的依赖项注入。这是ASP.NET核心项目的默认设置,但对于其他项目,您必须引用Microsoft.Extensions.Http和Microsoft.Extensions.DependencyInjection
然后,在创建服务容器时,只需调用AddHttpClient()
:
然后,您可以将HttpClient
注入到您的服务中,而幕后HttpClientFactory
将维护一个HttpClientHandler
对象池-保持DNS的新鲜度并防止出现问题
旧答案: Singleton是使用
HttpClient
的正确方法。有关详细信息,请参阅文章
Microsoft州:
HttpClient旨在实例化一次,并在应用程序的整个生命周期中重复使用。为每个请求实例化HttpClient类将耗尽重载下可用的套接字数量。这将导致SocketException错误。下面是一个正确使用HttpClient的示例
事实上,我们在应用程序中发现了这一点。我们的代码可以在foreach
循环中发出数百个API请求,对于每个迭代,我们都使用创建一个HttpClient
封装在中。很快,我们的MongoClient
就出现了一些令人恼火的错误,说它在尝试连接数据库时超时了。在阅读链接文章后,我们发现即使在处理了HttpClient
之后,也会耗尽可用的套接字
唯一需要注意的是,诸如DefaultRequestHeaders
和BaseAddress
之类的内容将应用于使用HttpClient的任何地方。作为单例,这可能贯穿整个应用程序。您仍然可以在应用程序中创建多个HttpClient
实例,但请注意,每次创建实例时,它们都会创建一个新的连接池,因此应该谨慎创建
正如hvaughan3所指出的,您也不能更改HttpClient使用的HttpMessageHandler
的实例,因此如果这对您很重要,您将需要使用该处理程序的单独实例。而HttpClient
应该被重用,这并不一定意味着我们必须使用单例来组织代码。请参阅。下文也引述
我来晚了,但这是我关于这个棘手话题的学习之旅
1.我们在哪里可以找到重用HttpClient的官方倡导者?
我是说,如果
以及,
这样的倡导者更好地记录在自己的API文档中,
而不是隐藏在许多“高级主题”、“性能(反)模式”中
或者其他的博客文章。
否则,一个新的学习者怎么能在为时已晚之前知道它呢
截至目前(2018年5月),谷歌搜索“c#httpclient”时的第一个搜索结果
指向,但根本没有提到这个意图。
嗯,新手的第1课是,
始终在MSDN帮助页面标题后单击“其他版本”链接,
您可能会在那里找到指向“当前版本”的链接。
在这个HttpClient案例中,它将为您带来最新的文档
我怀疑很多对这个话题不熟悉的开发人员
也没有找到正确的文档页,
这就是为什么这些知识没有被广泛传播,
当人们发现这一点时,他们感到惊讶
,
可能吧
2.使用
IDisposable
这一点有点离题,但仍然值得指出的是,看到人并不是巧合
在上面提到的那些博客文章中,他们指责了HttpClient
的IDisposable
接口
使他们倾向于使用(var client=new HttpClient()){…}
模式
然后引出问题
我相信这可以归结为一个未被说出的(错误的?)概念:
然而,当我们以这种风格编写代码时,它看起来确实是一件短命的事情:
using (var foo = new SomeDisposableObject())
{
...
}
从不提及IDisposable对象必须是短期的。
根据定义,IDisposable只是一种允许您释放非托管资源的机制。
没别的了。从这个意义上说,你最终会触发处置,
但它并不要求你以一种短命的方式这样做
因此,您的工作是正确选择何时触发处置,
基于真实对象的生命周期要求。
没有任何东西可以阻止您长期使用IDisposable:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
有了这个新的认识,现在我们再来看看,,
我们可以清楚地注意到,“修复程序”只初始化了一次HttpClient,但从未处理过它,
这就是为什么我们可以从它的netstat输出中看到,
连接保持在已建立状态,这意味着它尚未正确关闭。
如果它被关闭,它的状态将是及时等待。
实际上,在整个程序结束后只泄漏一个打开的连接并不是什么大问题,
还有博客
HttpService.Instance.sendData(...)
var services = new ServiceCollection();
services.AddHttpClient()
var serviceProvider = services.BuildServiceProvider();
using (var foo = new SomeDisposableObject())
{
...
}
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
System.InvalidOperationException: Concurrent reads or writes are not supported.\r\n at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()\r\n at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)\r\n at System.IO.Pipelines.Pipe.GetReadAsyncResult()\r\n at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.WriteBody(Boolean flush)","ClassName":"IISHttpContext","MethodName":"WriteBody","EventId":{"Id":3,"Name":"UnexpectedError"},"SourceContext":"Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer"