Come ottenere il corpo del contenuto da una chiamata httpclient?


108

Ho cercato di capire come leggere il contenuto di una chiamata httpclient e non riesco a ottenerlo. Lo stato di risposta che ottengo è 200, ma non riesco a capire come ottenere l'effettivo Json restituito, che è tutto ciò di cui ho bisogno!

Quello che segue è il mio codice:

async Task<string> GetResponseString(string text)
{
    var httpClient = new HttpClient();

    var parameters = new Dictionary<string, string>();
    parameters["text"] = text;
    Task<HttpResponseMessage> response = 
        httpClient.PostAsync(BaseUri, new FormUrlEncodedContent(parameters));

    return await response.Result.Content.ReadAsStringAsync();
}

E lo sto ottenendo semplicemente chiamandolo da un metodo:

Task<string> result =  GetResponseString(text);

E questo è quello che ottengo

response Id = 89, Status = RanToCompletion, Method = "{null}", Result = "StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:\r\n{\r\n Connection: keep-alive\r\n Date: Mon, 27 Oct 2014 21:56:43 GMT\r\n ETag: \"5a266b16b9dccea99d3e76bf8c1253e0\"\r\n Server: nginx/0.7.65\r\n Content-Length: 125\r\n Content-Type: application/json\r\n}" System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>

Aggiornamento: questo è il mio codice attuale per la risposta di Nathan di seguito

    async Task<string> GetResponseString(string text)
    {
        var httpClient = new HttpClient();

        var parameters = new Dictionary<string, string>();
        parameters["text"] = text;

        var response = await httpClient.PostAsync(BaseUri, new FormUrlEncodedContent(parameters));
        var contents = await response.Content.ReadAsStringAsync();

        return contents;
    }

E lo chiamo da questo metodo ...

 string AnalyzeSingle(string text)
    {
        try
        {
            Task<string> result = GetResponseString(text);
            var model = JsonConvert.DeserializeObject<SentimentJsonModel>(result.Result);

            if (Convert.ToInt16(model.pos) == 1)
            {
                _numRetries = 0;
                return "positive";
            }

            if (Convert.ToInt16(model.neg) == 1)
            {
                _numRetries = 0;
                return "negative";
            }

            if (Convert.ToInt16(model.mid) == 1)
            {
                _numRetries = 0;
                return "neutral";
            }

            return "";
        }
        catch (Exception e)
        {
            if (_numRetries > 3)
            {
                LogThis(string.Format("Exception caught [{0}] .... skipping", e.Message));
                _numRetries = 0;
                return "";
            }
            _numRetries++;
            return AnalyzeSingle(text);
        }
    }

E continua a funzionare per sempre, raggiunge la linea una var model = JsonConvert.DeserializeObject<SentimentJsonModel>(result.Result); volta e continua ad andare senza fermarsi a un altro punto di interruzione.

Quando metto in pausa l'esecuzione, dice

Id = Impossibile valutare l'espressione perché il codice del metodo corrente è ottimizzato., Stato = Impossibile valutare l'espressione perché il codice del metodo corrente è ottimizzato., Metodo = Impossibile valutare l'espressione perché il codice del metodo corrente è ottimizzato., Risultato = Impossibile valutare l'espressione perché il codice del metodo corrente è ottimizzato.

.. Continuo l'esecuzione, ma funziona per sempre. Non sono sicuro di quale sia il problema


Dove e come viene definito _numRetries?
— Nathan A

È nell'ambito della classe e viene inizializzato con uno 0 nel costruttore. AnalyseSingle () è l'unico posto in cui lo uso.
— Sherman Szeto

Stai eseguendo in modalità Debug? Il problema ottimizzato potrebbe essere dovuto al fatto che stai eseguendo in modalità di rilascio.
— Nathan A

Sono al momento su Debug / iisExpress
— Sherman Szeto

Risposte:


176

Il modo in cui utilizzi await / async è nella migliore delle ipotesi scadente e rende difficile seguirlo. Si stia mescolando awaitcon Task'1.Result, che è solo fonte di confusione. Tuttavia, sembra che tu stia guardando il risultato finale dell'attività, piuttosto che il contenuto.

Ho riscritto la tua funzione e la chiamata di funzione, che dovrebbe risolvere il tuo problema:

async Task<string> GetResponseString(string text)
{
    var httpClient = new HttpClient();

    var parameters = new Dictionary<string, string>();
    parameters["text"] = text;

    var response = await httpClient.PostAsync(BaseUri, new FormUrlEncodedContent(parameters));
    var contents = await response.Content.ReadAsStringAsync();

    return contents;
}

E la tua chiamata di funzione finale:

Task<string> result = GetResponseString(text);
var finalResult = result.Result;

O ancora meglio:

var finalResult = await GetResponseString(text);

Grazie!! Ho cercato di capire come funziona async / await nelle ultime due ore (MSDN + stackoverflow), ma ovviamente non l'ho ancora capito completamente. Ci sono risorse che suggeriresti?
— Sherman Szeto

1
Continua a giocarci e alla fine capirai come funziona. È un concetto ampio da comprendere tutto in una volta.
— Nathan A

Ho ancora problemi. Ho aggiornato il mio problema sul post originale. Il problema potrebbe essere che sto codificando per l'esecuzione sincrona, ma non sono sicuro di come risolvere il problema
— Sherman Szeto

1
HttpClient implementa IDisposable, quindi è meglio racchiuderlo in un'istruzione using.
— Payam

2
@ Payam mentre è vero che implementa, IDisposablenon dovresti racchiuderlo in una usingdichiarazione. È una rara eccezione alla regola. Vedi questo post per maggiori informazioni: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
— maxshuty

62

Se non si desidera utilizzare asyncè possibile aggiungere .Resultper forzare l'esecuzione del codice in modo sincrono:

private string GetResponseString(string text)
{
    var httpClient = new HttpClient();

    var parameters = new Dictionary<string, string>();
    parameters["text"] = text;

    var response = httpClient.PostAsync(BaseUri, new FormUrlEncodedContent(parameters)).Result;
    var contents = response.Content.ReadAsStringAsync().Result;

    return contents;
 }  

2
@nbushnell aggiungendo .Result a PostAsync lo rende non asincrono
— Mike

6
@ Mike non è quello che sta dicendo nbushnell? :-)
— PoeHaH

A cosa serve il tipo response? Ho un codice simile ma devo renderlo responseglobale, quindi ho bisogno del tipo. Grazie.
— Azurespot

1
@AzureSpot: il tipo di risposta è HttpResponseMessage.
— RWC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.