2016-06-20 24 views
24

Dato che .net HttpClient è stato progettato con riutilizzo in mente ed è destinato a essere long lived e memory leaks have been reported in istanze di breve durata. Quali linee guida ci sono dove si desidera effettuare chiamate riposanti verso un determinato endpoint utilizzando diversi token al portatore (o qualsiasi intestazione di autorizzazione) quando si chiama l'endpoint per più utenti?HttpClient singola istanza con diverse intestazioni di autenticazione

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

Dato il codice di cui sopra potrebbe essere chiamato da qualsiasi numero di filettatura di un'applicazione web è facilmente possibile che l'intestazione impostato nella prima riga non è lo stesso che viene utilizzato quando si chiama la risorsa.

Senza causare conflitti utilizzando i blocchi e mantenendo un'applicazione Web stateless qual è l'approccio consigliato per la creazione e l'eliminazione di HttpClients per un singolo endpoint (la mia pratica corrente è creare un singolo client per endpoint)?


Lifecycle

Anche se HttpClient fa indirettamente implementare l'interfaccia IDisposable , l'utilizzo raccomandato di HttpClient non è quello di disporre di esso dopo ogni richiesta. L'oggetto HttpClient è destinato a essere utilizzato come finché l'applicazione deve effettuare richieste HTTP. L'esistenza di un oggetto su più richieste abilita un posto per l'impostazione di DefaultRequestHeaders e impedisce di dover rispettare le cose come CredentialCache e CookieContainer su ogni richiesta, come era necessario con HttpWebRequest.

+0

Stai parlando di un numero relativamente piccolo di diverse intestazioni o lotti di autenticazione, ad esempio univoci per ogni utente? –

+0

@ToddMenier: sarebbe un'intestazione univoca per ciascun utente.Sarebbe quel token utente oauth. Penso che lo scott hannen mi abbia messo sulla strada giusta. Sembra che alcuni metodi di estensione saranno in ordine. – Bronumski

+0

Ciao @Bronumski, puoi condividere il modo in cui hai risolto questo? Sto avendo lo stesso problema con più thread aggiungendo la stessa intestazione ma con contenuti diversi. –

risposta

28

Se le intestazioni di solito saranno uguali, è possibile impostare DefaultRequestHeaders. Ma non è necessario usare quella proprietà per specificare le intestazioni. Come hai stabilito, non funzionerebbe se hai più thread che usano lo stesso client. Le modifiche alle intestazioni predefinite eseguite su un thread influiscono sulle richieste inviate su altri thread.

Sebbene sia possibile impostare le intestazioni predefinite sul client e applicarle a ciascuna richiesta, le intestazioni sono realmente proprietà della richiesta. Quindi, quando le intestazioni sono specifiche per una richiesta, devi solo aggiungerle alla richiesta.

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

Ciò significa che non è possibile utilizzare i metodi semplificati che non comportano la creazione di un HttpRequest. È necessario utilizzare

public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request) 

documentato here.

Esempio di metodi GET e POST fatto attraverso un metodo di estensione che consentono di manipolare l'intestazione della richiesta e più del HttpRequestMessage prima di essere inviato:

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

Questi potrebbe quindi essere utilizzato come la seguente:

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

Ottima soluzione. Appena implementato Aggiunto scorciatoia seguendo il modello sotto public static Task GetAsync (questo httpClient HttpClient, string uri, token stringa, CancellationToken cancellationToken) {return httpClient.GetAsync (uri, x => SetToken (x, token), cancellationToken); } void SetToken (richiesta HttpRequestMessage, stringa token, stringa type = "Bearer") –

Problemi correlati