2016-06-20 12 views
24

Vorausgesetzt, dass der .net HttpClient wurde mit der Wiederverwendung im Auge behalten und soll long lived und memory leaks have been reported in kurzlebigen Instanzen sein. Welche Hilfslinien gibt es, wenn Sie einen bestimmten Endpunkt unter Verwendung verschiedener Trägertokens (oder eines beliebigen Berechtigungsheaders) beim Aufrufen des Endpunkts für mehrere Benutzer erneut anrufen möchten?HttpClient Einzelinstanz mit verschiedenen Authentifizierungsheadern

private void CallEndpoint(string resourceId, string bearerToken) { 
    httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("bearer", bearerToken); 
    var response = await httpClient.GetAsync($"resource/{resourceid}"); 
} 

durch eine beliebige Anzahl von Threads auf einer Web-Anwendung gegeben werden, den oben genannten Code könnte es leicht möglich ist genannt, dass der Header in der ersten Zeile gesetzt nicht die gleiche ist, die verwendet wird, wenn die Ressource aufrufen.

Ohne Konflikte mit Sperren zu verursachen und eine zustandslose Webanwendung zu verwalten, ist der empfohlene Ansatz zum Erstellen und Entsenden von HttpClients für einen einzelnen Endpunkt (Meine derzeitige Praxis besteht darin, einen einzelnen Client pro Endpunkt zu erstellen)?


Lifecycle

Obwohl Httpclient nicht indirekt die Schnittstelle IDisposable implementieren, ist die empfohlene Verwendung von Httpclient ist nicht nach jeder Anforderung zu entsorgen. Das HttpClient-Objekt soll so lange wie leben, solange Ihre Anwendung HTTP-Anforderungen stellen muss. Wenn ein Objekt für mehrere Anfragen vorhanden ist, können Sie DefaultRequestHeaders festlegen und verhindern, dass Sie bei jeder Anfrage die Eigenschaften wie CredentialCache und CookieContainer neu festlegen müssen, ebenso wie mit HttpWebRequest.

+0

Sprechen Sie über eine relativ kleine Anzahl von verschiedenen Auth-Headern oder Chargen, wie für jeden Benutzer einzigartig? –

+0

@ ToddMenier - Es wäre ein eindeutiger Header für jeden Benutzer.Es wäre, dass Benutzer oauth Token. Ich denke scott hannen hat mich auf den richtigen weg gebracht. Sieht so aus, als wären einige Erweiterungsmethoden in Ordnung. – Bronumski

+0

Hallo @Bronumski, kannst du teilen, wie du das gelöst hast? Ich habe das gleiche Problem mit mehreren Threads, die denselben Header aber mit anderem Inhalt hinzufügen. –

Antwort

28

Wenn Ihre Header normalerweise identisch sind, können Sie DefaultRequestHeaders einstellen. Sie müssen diese Eigenschaft jedoch nicht zum Angeben von Headern verwenden. Wie Sie festgestellt haben, würde das einfach nicht funktionieren, wenn Sie mehrere Threads mit demselben Client verwenden möchten. Änderungen an den Standardheadern, die in einem Thread vorgenommen wurden, würden sich auf Anforderungen auswirken, die an andere Threads gesendet werden.

Obwohl Sie Standard-Header auf dem Client festlegen und sie für jede Anforderung anwenden können, sind die Header wirklich Eigenschaften der Anforderung. Wenn die Header für eine Anfrage spezifisch sind, würden Sie sie einfach zur Anfrage hinzufügen.

request.Headers.Authorization = new AuthenticationHeaderValue("bearer", bearerToken); 

Das bedeutet, dass Sie nicht die vereinfachten Methoden verwenden, die nicht mit einem HttpRequest zu schaffen. Sie müssen verwenden

public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request) 

dokumentiert here.

Beispiel von GET und POST-Methoden durch eine Erweiterung Methode durchgeführt, mit denen Sie den Request-Header und der HttpRequestMessage zu manipulieren, bevor es gesendet wird:

public static Task<HttpResponseMessage> GetAsync 
    (this HttpClient httpClient, string uri, Action<HttpRequestMessage> preAction) 
{ 
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri); 

    preAction(httpRequestMessage); 

    return httpClient.SendAsync(httpRequestMessage); 
} 

public static Task<HttpResponseMessage> PostAsJsonAsync<T> 
    (this HttpClient httpClient, string uri, T value, Action<HttpRequestMessage> preAction) 
{ 
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri) 
    { 
     Content = new ObjectContent<T> 
      (value, new JsonMediaTypeFormatter(), (MediaTypeHeaderValue)null) 
    }; 
    preAction(httpRequestMessage); 

    return httpClient.SendAsync(httpRequestMessage); 
} 

Diese könnten dann wie folgt verwendet werden:

var response = await httpClient.GetAsync("token", 
    x => x.Headers.Authorization = new AuthenticationHeaderValue("basic", clientSecret)); 
+0

Große Lösung. Gerade umgesetzt. Shortcut folgenden Muster unter öffentlichen statischen Task hinzugefügt GetAsync (diese HttpClient httpClient, Zeichenfolge uri, String-Token, CancellationToken cancellationToken) {zurück httpClient.GetAsync (uri, x => SetToken (x, Token), cancellationToken); } void SetToken (HttpRequestMessage-Anforderung, Zeichenfolge-Token, Zeichenfolge-Typ = "Bearer") –