7

Tworzymy wrapper dla HttpClient. Ponieważ będziemy postępować zgodnie z wytycznymi optymalizacji wydajności od https://github.com/mspnp/performance-optimization. Chcemy uniknąć wzorca antypoślizgowego - niewłaściwej instancji wspomnianej w tym dokumencie. Przekazałem te wskazówki mojemu zespołowi, aby używać statycznego HttpClient. Opinie, które otrzymałem, dotyczą bezpieczeństwa gwintów. Każde żądanie ma nagłówek zawierający roszczenie użytkownika. Ponieważ mam statyczny HttpClient, czy będzie bezpieczny dla wątków? Jeśli mamy kilka żądań, które uderzają w kod (na przykład GET) w tym samym czasie, czy będzie to warunek wyścigu do ustawienia nagłówka? Mamy implementację jak poniżej.Statyczny wątek HttpClient bezpieczny na ASP.net HttpRequest

public class HttpClientHelper{ 
private static readonly HttpClient _HttpClient; 
static HttpClientHelper() { 
     HttpClient = new HttpClient(); 
     HttpClient.Timeout = TimeSpan.FromMinutes(SOME_CONFIG_VALUE); 
} 

public async Task<HttpResponseMessage> CallHttpClientPostAsync(string requestUri, HttpContent requestBody) 
{ 
    AddHttpRequestHeader(httpClient); 
    var response = await httpClient.PostAsync(requestUri, requestBody); //Potential thread synchronization issue??? 
    return response; 
} 

public HttpResponseMessage CallHttpClientGet(string requestUri) 
{ 
    AddHttpRequestHeader(httpClient); 
    var response = httpClient.GetAsync(requestUri).Result; //Potential thread synchronization issue??? 
    return response; 
} 

private void AddHttpRequestHeader(HttpClient client) 
{ 
    string HeaderName = "CorrelationId"; 
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(Properties.Settings.Default.HttpClientAuthHeaderScheme, GetTokenFromClaims()); //Race condition??? 
    if (client.DefaultRequestHeaders.Contains(HeaderName)) 
     client.DefaultRequestHeaders.Remove(HeaderName); 
    client.DefaultRequestHeaders.Add(HeaderName, Trace.CorrelationManager.ActivityId.ToString()); 
} 

}

+1

Każdy powód, dla którego 'CallHttpClientGet' nie jest asynchronizowany? Przez wywołanie '.Result' blokujesz wątek i zapraszanie potencjalnych zakleszczeń. –

Odpowiedz

10

Twój zespół jest poprawna, to jest daleko od bezpiecznej wątku. Rozważmy następujący scenariusz:

  • Wątek A ustawia nagłówek CorrelationId na "foo".
  • Wątek B ustawia nagłówek CorrelationId na "bar".
  • Wątek A wysyła żądanie, które zawiera komunikat korelacji wątku B.

Lepszym rozwiązaniem byłoby wasze metody CallXXX tworzyć nowe HttpRequestMessage obiektów i ustawić nagłówek na te i używać HttpClient.SendAsync, aby nawiązać połączenie.

Należy pamiętać, że ponowne użycie instancji HttpClient jest korzystne tylko w przypadku wielokrotnych połączeń z tym samym hostem.

+0

"Należy pamiętać, że ponowne używanie instancji HttpClient jest korzystne tylko wtedy, gdy wykonujesz wiele połączeń z tym samym hostem" - czy masz do tego odniesienia? –

+2

@OhadSchneider Jest oparty na [porady Daryla Millera] (https://stackoverflow.com/a/22561368/62600) aby użyć jednej instancji "dla każdego odrębnego API, z którym się łączysz". Powód jest taki, że korzyści związane z wydajnością (bez konieczności otwierania nowego połączenia itp.) Są istotne tylko dla hosta, podobnie jak niektóre właściwości HttpClient, takie jak DefatultHeaders. Jednak znany obecnie problem z gniazdem (https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) może nieco zmienić moją radę. Czy system Windows może odzyskać gniazdo w czasie TIME_WAIT do użytku z innym hostem? Nie jestem pewny. Wysłałem pytanie do tego artykułu. –

Powiązane problemy