在阅读这篇关于blog post的www.asp.net和官方说明之后:
HttpClient旨在实例化一次,并在应用程序的整个生命周期中重复使用。特别是在服务器应用程序中,为每个请求创建一个新的HttpClient实例将耗尽重负载下可用的套接字数量。这将导致SocketException错误。
我发现我们的代码在每次调用时都处理了HttpClient。我正在更新我们的代码,以便我们重用HttClient,但我关心的是我们的工具,但不是线程安全的。
以下是新代码的当前草案:
对于单元测试,我们为HttpClient实现了一个包装器,消费者调用包装器:
public class HttpClientWrapper : IHttpClient
{
private readonly HttpClient _client;
public Uri BaseAddress
{
get
{
return _client.BaseAddress;
}
set
{
_client.BaseAddress = value;
}
}
public HttpRequestHeaders DefaultRequestHeaders
{
get
{
return _client.DefaultRequestHeaders;
}
}
public HttpClientWrapper()
{
_client = new HttpClient();
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, String userOrProcessName)
{
IUnityContainer container = UnityCommon.GetContainer();
ILogService logService = container.Resolve<ILogService>();
logService.Log(ApplicationLogTypes.Debug, JsonConvert.SerializeObject(request), userOrProcessName);
return _client.SendAsync(request);
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing && _client != null)
{
_client.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
这是一个叫做的服务:
public class EnterpriseApiService : IEnterpriseApiService
{
private static IHttpClient _client;
static EnterpriseApiService()
{
IUnityContainer container = UnityCommon.GetContainer();
IApplicationSettingService appSettingService = container.Resolve<IApplicationSettingService>();
_client = container.Resolve<IHttpClient>();
}
public EnterpriseApiService() { }
public Task<HttpResponseMessage> CallApiAsync(Uri uri, HttpMethod method, HttpContent content, HttpRequestHeaders requestHeaders, bool addJsonMimeAccept = true)
{
IUnityContainer container = UnityCommon.GetContainer();
HttpRequestMessage request;
_client.BaseAddress = new Uri(uri.GetLeftPart(UriPartial.Authority));
if (addJsonMimeAccept)
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request = new HttpRequestMessage(method, uri.AbsoluteUri);
// Removed logic that built request with content, requestHeaders and method
return _client.SendAsync(request, UserOrProcessName);
}
}
我的问题:
更新:由于我已经删除了USING语句,并且Garage Collection没有调用Dispose,我将采用更安全的方法在方法中创建新实例。要在线程生存期内重用HttpClient的实例,它需要对逻辑进行重要的重写,因为该方法为每次调用设置HttpClient属性。
我不认为你想要一个应用程序范围的实例。你想要每个线程一个实例。否则你将无法获得很好的表现!此外,这将解决您的问题#3和#4,因为没有两个线程将同时访问同一个HttpClient。
对于那些幸运地使用.NET Core的人来说,这是相当简单的。
正如John Wu如此雄辩地说,你不需要单身人士,而是每个请求单身。因此,AddScoped<TService>()
方法就是你所追求的。
在你的ConfigureServices(IServiceCollection services)
方法:
services.AddScoped<HttpClient>();
消费:
public class HomeController
{
readonly HttpClient client;
public HomeController (HttpClient client)
{
this.client = client;
}
//rest of controller code
}
由于它调用SendAsync(),我们是否保证响应被映射回正确的调用者?我想确认响应不会转到另一个调用者。
这将通过回调指针处理。它与使用HttpClient作为单例无关。更多细节 - https://stackoverflow.com/a/42307650/895724