reuse problem close c# asp.net-mvc static async-await dotnet-httpclient

close - httpclient problem c#



Implementación HttpClient Singleton en ASP.NET MVC (1)

¿De verdad quieres una instancia?

No creo que quieras una instancia para toda la aplicación. Quieres una instancia por hilo. De lo contrario, no obtendrás un buen rendimiento. Además, esto resolverá sus preguntas # 3 y # 4, ya que no habrá dos subprocesos que tengan acceso al mismo HttpClient al mismo tiempo.

No necesitas un singleton

Solo use Container.Resolve con PerThreadLifetimeManager .

Después de leer esta publicación de blog y esta nota oficial en www.asp.net :

HttpClient está destinado a ser instanciado una vez y reutilizado a lo largo de la vida de una aplicación. Especialmente en aplicaciones de servidor, la creación de una nueva instancia de HttpClient para cada solicitud agotará la cantidad de sockets disponibles bajo cargas pesadas. Esto dará como resultado errores SocketException.

Descubrí que nuestro código estaba eliminando el HttpClient en cada llamada. Estoy actualizando nuestro código para que reutilicemos el HttClient, pero me preocupa nuestro implemento pero no es seguro para subprocesos.

Aquí está el borrador actual del nuevo código:

Para Unit Testing, implementamos un contenedor para HttpClient, los consumidores llaman al contenedor:

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 }

Aquí hay un servicio que llama:

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); } }

Mis preguntas:

  1. ¿Es este un enfoque apropiado para reutilizar el objeto HttpClient?
  2. ¿El campo estático _httpClient (poblado con el constructor estático) se comparte para todas las instancias de EnterpriseApiService? Quería confirmar ya que los métodos de instancia me llaman.
  3. Cuando se invoca CallApiAsync (), cuando eso hace cambios en el HttpClient estático, como el "_client.DefaultRequestHeaders.Accept.Add (new MediaTypeWithQualityHeaderValue (" application / json "))" esos valores pueden ser sobrescritos por otro proceso antes de la última se llama a la línea "_client.SendAsync"? Me preocupa que a la mitad del proceso de CallApiAsync () la instancia estática se actualice.
  4. Dado que está llamando a SendAsync (), ¿se garantiza que la respuesta se asigna a la persona que llama correcta? Quiero confirmar que la respuesta no va para otra persona que llama.

Actualización: desde que eliminé las instrucciones de USO, y la Colección de Garage no llama a Dispose, me voy a ir con el enfoque más seguro de crear una nueva instancia dentro del método. Para reutilizar una instancia de HttpClient incluso dentro del tiempo de vida del subproceso, se requeriría una reelaboración significativa de la lógica porque el método establece las propiedades de HttpClient por llamada.