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.