2014-06-27 7 views
6

Perché è necessario in .NET Web API avere un metodo che legge il contenuto di una risposta HTTP in modo asincrono, dato che esiste già un metodo per effettuare la richiesta in modo asincrono? Detto in un altro modo, se sto usando HttpClient.GetAsync (o PostAsync, o PutAsync, ecc.), Il codice è davvero più asincrono anche leggendo il contenuto in modo asincrono? Se sì, come/perché?Perché attendere sia la richiesta asincrona che la lettura dei suoi contenuti?

è questa:

using (var client = new HttpClient()) { 
    var response = await client.GetAsync("..."); 
    response.EnsureSuccessStatusCode(); 
    return await response.Content.ReadAsAsync<Foo>(); 
} 

meglio di questo:

using (var client = new HttpClient()) { 
    var response = await client.GetAsync("..."); 
    response.EnsureSuccessStatusCode(); 
    return response.Content.ReadAsAsync<Foo>().Result; 
} 

e perché?

+1

Pensi che abbia qualcosa a che fare con il supporto di contenuti bufferizzati, forse? In realtà, il contenuto sarebbe ancora restituito per intero quando è stato ripreso. Tuttavia non è un'operazione legata al calcolo, anche confusa! Buona domanda però! I documenti – brumScouse

+2

per GetAsync dicono "L'oggetto compito restituito verrà completato dopo aver letto l'intera risposta (incluso il contenuto)." –

risposta

7

Perché è necessario in .NET Web API avere un metodo che legge il contenuto di una risposta HTTP in modo asincrono, dato che esiste già un metodo per effettuare la richiesta in modo asincrono?

Perché possibile. Questi due metodi fanno cose diverse. Il primo invia una richiesta di rete via cavo, la seconda legge dallo Stream ricevuto.

Poiché sia ​​la richiesta di rete che la lettura da uno stream sono operazioni associate all'IO, è possibile sfruttare l'api asincrona che espongono.

se sto usando HttpClient.GetAsync (o PostAsync, o PutAsync, ecc), è il codice in realtà più asincrona anche la lettura del contenuto in modo asincrono? Se sì, come/perché?

Sembra un po 'strano dire che qualcosa è "più asincrono". Ma sì, il precedente esempio è più asincrono rispetto al secondo.

Consente di riprovare il seguente scenario: Si crea una libreria che è responsabile della comunicazione con un servizio di terze parti. Esporre un metodo, chiamiamolo FooAsync, che restituisce un valore molto grande List<Foo>. L'utente sa che l'API è asincrona, quindi si sente in dovere di chiamarlo dal thread dell'interfaccia utente e non si preoccupa di bloccarlo per una lunga durata.

Ora, vediamo cosa happeneds quando fa la chiamata con ogni metodo:

  1. Eseguiamo FooAsync e la richiesta HTTP è fatto, cedendo il controllo al chiamante quando si raggiunge il primo await. Quindi, continua l'esecuzione toccando il secondo await che legge dallo stream ricevuto, restituendo nuovamente il controllo al chiamante fino a quando non termina. Per tutto il tempo, l'interfaccia utente è libera di elaborare i messaggi poiché entrambe le operazioni principali vengono eseguite asincrone.

  2. Eseguiamo FooAsync e facciamo la richiesta http. diamo il controllo sul primo await, tutto va bene. Quindi, riceviamo la risposta e leggiamo il flusso sottostante in modo sincrono. Mentre leggiamo (e ricordiamo che stiamo leggendo un flusso molto grande) il thread dell'interfaccia utente è bloccato sull'operazione IO, incapace di elaborare altri messaggi.

Il nostro secondo caso è decisamente indesiderato e persino peggio, inaspettato.Abbiamo detto all'utente che sta ricevendo un'API async, ma finiamo per bloccare per un periodo piuttosto lungo. Non solo, ma se Task.Result viene chiamato dal thread dell'interfaccia utente, potrebbe deadlock.

Il vantaggio dell'utilizzo di await in entrambe le operazioni consiste nel creare un'api veramente asincrona, senza perdere tempo nel bloccare le operazioni di I/O e non sorprendere nessuno che chiama il metodo bloccando.

Suggerisco di leggere Best Practices in Asynchronous Programming che parla di tutti quei casi limite.

Per concludere, se si può andare async "fino in fondo", farlo.

+2

La lettura dalla memoria non è un'operazione legata all'IO. Intendevi qualcosa come "leggere la risposta dalla rete"? – svick

+0

Suppongo che la lettura del flusso di risposta possa essere eseguita in modo asincrono. Risolto il problema con la mia risposta –