Estoy creando una aplicación en .Net Core 2.1 y estoy usando un cliente http para solicitudes web. El problema es que tengo que enviar llamadas paralelas para ahorrar tiempo y para eso estoy usando el método Task.WhenAll() pero cuando presiono este método aparece el error "Esta instancia ya inició una o más solicitudes. Las propiedades solo se pueden modificar antes de enviar la primera solicitud" Anteriormente estaba usando RestSharp y todo estaba bien, pero quiero usar httpclient. Aquí está el código:
public async Task<User> AddUser(string email) { var url = "user/"; _client.BaseAddress = new Uri("https://myWeb.com/"); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Constants."application/json")); _client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var json = new {email = email } var response = await _client.PostAsJsonAsync(url,json); if (response .IsSuccessStatusCode) { ....Aquí está el constructor:
private readonly HttpClient _httpClient; public UserRepository(HttpClient httpClient) { _httpClient = httpClient; }Método de llamada:
var user1 = AddUser("user@user.com"); var user2 = AddUser("test@test.com"); await Task.WhenAll(user1, user2);y aquí está la configuración de inicio:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();Entonces, ¿qué estoy haciendo mal? ¿Necesito cambiar AddSingleton con AddTransient() o hay algún otro problema? Una pregunta más, ¿necesito usar _client.Dispose() después de la respuesta porque el tutorial que seguí no usó el método dispose, por lo que estoy un poco confundido con eso?
Funciona bien cuando agrega la URL de solicitud y los encabezados en el mensaje, en lugar de en el cliente. Por lo tanto, es mejor no asignar a BaseAddress o al encabezado DefaultRequestHeaders si los usará para muchas solicitudes.
HttpRequestMessage msg = new HttpRequestMessage { Method = HttpMethod.Put, RequestUri = new Uri(url), Headers = httpRequestHeaders; }; httpClient.SendAsync(msg);El problema se debe al restablecimiento de BaseAddress y encabezados para la misma instancia de httpclient.
Lo intenté
if (_httpClient.BaseAddress == null)pero no estoy interesado en esto.
En mi opinión, una mejor solución es usar httpclientFactory. Esto terminará y recolectará basura la instancia del cliente http después de su uso.
private readonly IHttpClientFactory _httpClientFactory; public Foo (IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public httpresponse Bar () { _httpClient = _httpClientFactory.CreateClient(command.ClientId); using var response = await _httpclient.PostAsync(uri,content); return response; // here as there is no more reference to the _httpclient, the garbage collector will clean // up the _httpclient and release that instance. Next time the method is called a new // instance of the _httpclient is created }Tal vez mis dos centavos ayuden a alguien.
Me encontré con este problema al actualizar la página al depurar la aplicación.
Estaba usando un singleton, pero cada actualización intentaba establecer la dirección base. Así que simplemente lo envolví en un cheque para ver si la dirección base ya se había configurado.
El problema para mí fue que estaba tratando de configurar la dirección base, aunque ya estaba configurada. No puede hacer esto con un httpClient.
if (_httpClient.BaseAddress == null) { _httpClient.BaseAddress = new Uri(baseAddress); }HttpClient.DefaultRequestHeaders (y BaseAddress ) solo deben establecerse una vez, antes de realizar cualquier solicitud. HttpClient solo es seguro de usar como singleton si no lo modifica una vez que está en uso.
En lugar de configurar DefaultRequestHeaders , configure los encabezados en cada HttpRequestMessage que envíe.
var request = new HttpRequestMessage(HttpMethod.Post, url); request.Headers.Accept.Clear(); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); request.Content = new StringContent("{...}", Encoding.UTF8, "application/json"); var response = await _client.SendAsync(request, CancellationToken.None); Reemplace "{...}" con su JSON.