【发布时间】:2016-10-24 21:54:31
【问题描述】:
阅读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);
}
}
我的问题:
- 这是重用 HttpClient 对象的合适方法吗?
- 是否为 EnterpriseApiService 的所有实例共享静态 _httpClient 字段(使用静态构造函数填充)?我想确认一下,因为它是由实例方法调用的。
- 调用 CallApiAsync() 时,如果对静态 HttpClient 进行更改,例如“_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”))”,这些值可能会被另一个进程覆盖在最后一行“_client.SendAsync”被调用之前?我担心在处理 CallApiAsync() 的过程中会更新静态实例。
- 既然调用的是 SendAsync(),我们是否保证响应映射回正确的调用者?我想确认回复不会发给其他来电者。
更新: 由于我已经删除了 USING 语句,并且 Garage Collection 没有调用 Dispose,因此我将采用更安全的方法,即在方法中创建一个新实例。即使在线程生命周期内,要重用 HttpClient 的实例,也需要对逻辑进行重大修改,因为该方法会在每次调用时设置 HttpClient 属性。
【问题讨论】:
标签: c# asp.net-mvc static async-await dotnet-httpclient