Wie erhalte ich den Inhalt eines httpclient-Aufrufs?

107

Ich habe versucht herauszufinden, wie man den Inhalt eines httpclient-Aufrufs liest, und ich kann ihn anscheinend nicht verstehen. Der Antwortstatus, den ich erhalte, ist 200, aber ich kann nicht herausfinden, wie ich zu dem tatsächlich zurückgegebenen Json komme, was alles ist, was ich brauche!

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

Und ich bekomme es nur von einer Methode aufzurufen:

Task<string> result =  GetResponseString(text);

Und das bekomme ich

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>

Update: Dies ist mein aktueller Code gemäß Nathans Antwort unten

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

Und ich nenne es von dieser Methode ....

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

Und es läuft für immer weiter, es trifft die Linie var model = JsonConvert.DeserializeObject<SentimentJsonModel>(result.Result); einmal und es geht weiter, ohne an einem anderen Haltepunkt anzuhalten.

Wenn ich die Ausführung pausiere, heißt es

Id = Ausdruck kann nicht ausgewertet werden, weil der Code der aktuellen Methode optimiert ist., Status = Ausdruck kann nicht ausgewertet werden, weil der Code der aktuellen Methode optimiert ist., Methode = Ausdruck kann nicht ausgewertet werden, weil der Code der aktuellen Methode optimiert ist., Ergebnis = Ausdruck kann nicht ausgewertet werden, da der Code der aktuellen Methode optimiert ist.

Ich setze die Ausführung fort, aber es läuft nur für immer. Ich bin mir nicht sicher, wo das Problem liegt

Sherman Szeto
quelle
Wo und wie wird _numRetries definiert?
Nathan A
Es befindet sich im Bereich der Klasse und wird im Konstruktor mit einer 0 initialisiert. AnalyzeSingle () ist der einzige Ort, an dem ich es benutze.
Sherman Szeto
Laufen Sie im Debug-Modus? Das optimierte Problem liegt möglicherweise darin, dass Sie im Release-Modus ausgeführt werden.
Nathan A
Ich bin derzeit auf Debug / iisExpress
Sherman Szeto

Antworten:

175

Die Art und Weise, wie Sie await / async verwenden, ist bestenfalls schlecht und es ist schwierig, dem zu folgen. Sie mischenawait mit Task'1.Result, was nur verwirrend ist. Es sieht jedoch so aus, als würden Sie eher ein endgültiges Aufgabenergebnis als den Inhalt betrachten.

Ich habe Ihre Funktion und Ihren Funktionsaufruf umgeschrieben, wodurch Ihr Problem behoben werden sollte:

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

Und Ihr letzter Funktionsaufruf:

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

Oder noch besser:

var finalResult = await GetResponseString(text);
Nathan A.
quelle
Vielen Dank!! Ich habe in den letzten Stunden versucht herauszufinden, wie Async / Warten funktioniert (MSDN + Stackoverflow), aber ich habe es offensichtlich noch nicht vollständig verstanden. Gibt es Ressourcen, die Sie vorschlagen würden?
Sherman Szeto
1
Spielen Sie einfach weiter damit herum und Sie werden irgendwann den Dreh raus bekommen. Es ist ein großes Konzept, alles auf einmal zu erfassen.
Nathan A
Ich habe immer noch Probleme. Ich habe mein Problem im ursprünglichen Beitrag aktualisiert. Das Problem kann sein, dass ich für die synchrone Ausführung codiere, aber ich bin nicht sicher, wie ich dieses Problem lösen soll
Sherman Szeto
1
HttpClient implementiert IDisposable, daher ist es besser, es in eine using-Anweisung zu packen.
Payam
2
@Payam, obwohl es wahr ist, dass es implementiert IDisposable, sollten Sie es nicht in eine usingAnweisung einschließen . Es ist eine seltene Ausnahme von der Regel. Weitere Informationen finden Sie in diesem Beitrag: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty
62

Wenn Sie nicht verwenden möchten, können asyncSie hinzufügen .Result, um die synchrone Ausführung des Codes zu erzwingen:

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
quelle
2
@nbushnell Hinzufügen von .Result zu Ihrem PostAsync macht das es nicht asynchron
Mike
6
@ Mike ist das nicht was nbushnell sagt? :-)
PoeHaH
Wofür ist der Typ? response ? Ich habe einen ähnlichen Code, aber ich muss responseglobal machen , also brauche ich den Typ. Vielen Dank.
Azurespot
1
@ AzureSpot: Der Antworttyp ist HttpResponseMessage.
RWC