7

Wir erstellen einen Wrapper für HttpClient. Wir werden die Leitlinien zur Leistungsoptimierung von https://github.com/mspnp/performance-optimization befolgen. Wir wollen Anti-Pattern vermeiden - Unsaubere Instanziierung, die in diesem Dokument erwähnt wird. Ich habe diese Anleitung an mein Team weitergeleitet, um den statischen HttpClient zu verwenden. Das Feedback, das ich bekommen habe, ist auf Thread-Sicherheit. Jede Anfrage hat einen Header, der den Benutzeranspruch enthält. Da ich einen statischen HttpClient habe, wird es Thread-sicher sein? Wenn wir mehrere Anfragen gleichzeitig auf den Code (zum Beispiel GET) haben, wird es eine Race Condition sein, Header zu setzen? Wir haben die Implementierung wie folgt.Statische HttpClient Thread sicher auf 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

Gibt es einen Grund, warum 'CallHttpClientGet' nicht asynchron ist? Durch Aufruf von '.Result' blockieren Sie den Thread und laden potenzielle Deadlocks ein. –

Antwort

10

Ihr Team ist richtig, das ist noch lange Thread-sicher. Stellen Sie sich dieses Szenario vor:

  • Thread A setzt CorrelationId-Header auf "foo".
  • Thread B setzt CorrelationId-Header auf "bar".
  • Thread A sendet Anforderung, die CorrelationId von Thread B enthält.

Ein besserer Ansatz wäre für Ihre CallXXX Methoden neue HttpRequestMessage Objekte zu erstellen, und stellen Sie den Header auf diejenigen, und verwenden Sie HttpClient.SendAsync den Anruf zu tätigen.

Beachten Sie auch, dass die erneute Verwendung von HttpClient Instanzen nur dann von Vorteil ist, wenn Sie mehrere Aufrufe an denselben Host vornehmen.

+0

"Beachten Sie auch, dass die erneute Verwendung von HttpClient-Instanzen nur dann von Vorteil ist, wenn Sie mehrere Aufrufe an denselben Host senden" - haben Sie eine Referenz dafür? –

+2

@OhadSchneider Es basiert auf dem Rat von Daryl Miller (https://stackoverflow.com/a/22561368/62600), eine Instanz "für jede einzelne API zu verwenden, mit der Sie sich verbinden". Der Grund dafür ist, dass Leistungsvorteile (keine neue Verbindung öffnen usw.) nur pro Host relevant sind, ebenso wie bestimmte HttpClient-Eigenschaften wie DefatultHeaders. Allerdings könnte das jetzt berühmte [Socket-Problem] (https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) meinen Rat ein wenig ändern. Kann Windows ein Socket in TIME_WAIT für die Verwendung mit einem anderen Host zurückfordern? Ich bin mir nicht sicher. Ich habe die Frage zu diesem Artikel gestellt. –