Comment obtenir le corps du contenu d'un appel httpclient?

109

J'ai essayé de comprendre comment lire le contenu d'un appel httpclient, et je n'arrive pas à l'obtenir. Le statut de réponse que j'obtiens est 200, mais je ne peux pas comprendre comment accéder au Json réel renvoyé, ce qui est tout ce dont j'ai besoin!

Voici mon code:

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

Et je l'obtiens simplement en l'appelant à partir d'une méthode:

Task<string> result =  GetResponseString(text);

Et c'est ce que je reçois

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>

Mise à jour: Ceci est mon code actuel selon la réponse de Nathan ci-dessous

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

Et je l'appelle à partir de cette méthode ...

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

Et il continue à fonctionner pour toujours, il atteint la ligne une var model = JsonConvert.DeserializeObject<SentimentJsonModel>(result.Result); fois, et il continue à aller sans s'arrêter à un autre point d'arrêt.

Quand je suspends l'exécution, ça dit

Id = Impossible d'évaluer l'expression car le code de la méthode actuelle est optimisé., Statut = Impossible d'évaluer l'expression car le code de la méthode actuelle est optimisé., Méthode = Impossible d'évaluer l'expression car le code de la méthode actuelle est optimisé., Résultat = Impossible d'évaluer l'expression car le code de la méthode actuelle est optimisé.

.. Je continue l'exécution, mais elle s'exécute pour toujours. Je ne sais pas quel est le problème

Sherman Szeto
la source
Où et comment _numRetries est-il défini?
Nathan A
Il est dans la portée de la classe et est initialisé avec un 0 dans le constructeur. AnalyzeSingle () est le seul endroit où je l'utilise.
Sherman Szeto
Exécutez-vous en mode débogage? Le problème optimisé peut être dû au fait que vous exécutez en mode Release.
Nathan A
Je suis actuellement sur Debug / iisExpress
Sherman Szeto

Réponses:

176

La façon dont vous utilisez await / async est au mieux médiocre, et elle est difficile à suivre. Vous mélangez awaitavec Task'1.Result, ce qui est juste déroutant. Cependant, il semble que vous regardiez le résultat final de la tâche plutôt que le contenu.

J'ai réécrit votre fonction et votre appel de fonction, ce qui devrait résoudre votre problème:

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

Et votre dernier appel de fonction:

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

Ou encore mieux:

var finalResult = await GetResponseString(text);
Nathan A
la source
Merci!! J'ai essayé de comprendre comment async / await fonctionne ces dernières heures (MSDN + stackoverflow), mais je ne l'ai évidemment pas encore pleinement compris. Y a-t-il des ressources que vous suggérez?
Sherman Szeto
1
Continuez simplement à jouer avec et vous finirez par comprendre. C'est un grand concept à saisir d'un seul coup.
Nathan A
J'ai toujours des problèmes. J'ai mis à jour mon problème sur le message d'origine. Le problème est peut-être que je codifie pour une exécution synchrone, mais je ne sais pas comment résoudre ce problème
Sherman Szeto
1
HttpClient implémente IDisposable, il est donc préférable de l'envelopper dans une instruction using.
Payam
2
@Payam alors qu'il est vrai qu'il implémente, IDisposablevous ne devez pas l'envelopper dans une usingdéclaration. C'est une rare exception à la règle. Voir cet article pour plus d'informations: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty
62

Si vous ne souhaitez pas utiliser, asyncvous pouvez ajouter .Resultpour forcer le code à s'exécuter de manière synchrone:

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;
 }  
nbushnell
la source
2
@nbushnell l'ajout de .Result à votre PostAsync rend le it non asynchrone
Mike
6
@Mike n'est-ce pas ce que dit nbushnell? :-)
PoeHaH
À quoi sert le type response? J'ai un code similaire mais je dois le rendre responseglobal, donc j'ai besoin du type. Merci.
Azurespot
1
@AzureSpot: Le type de réponse est HttpResponseMessage.
RWC