Як отримати тіло вмісту за допомогою дзвінка httpclient?


108

Я намагався зрозуміти, як прочитати вміст дзвінка httpclient, і я не можу його зрозуміти. Я отримав статус відповіді - 200, але я не можу зрозуміти, як дістатися до фактичного повернення Джсона, що все, що мені потрібно!

Наступний мій код:

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

І я отримую це, просто називаючи його методом:

Task<string> result =  GetResponseString(text);

І це я отримую

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>

Оновлення: це мій поточний код на відповідь Натана нижче

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

І я називаю це від цього методу….

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

І він продовжує працювати вічно, Він потрапляє на лінію var model = JsonConvert.DeserializeObject<SentimentJsonModel>(result.Result); Один раз, і продовжує йти, не зупиняючись на іншому місці розриву.

Коли я призупиняю виконання, воно говорить

Id = Неможливо оцінити вираз, оскільки оптимізовано код поточного методу., Статус = Неможливо оцінити вираз, оскільки оптимізовано код поточного методу., Метод = Неможливо оцінити вираз, оскільки код поточного методу оптимізований., Результат = Неможливо оцінити вираз, оскільки код поточного методу оптимізований.

.. Я продовжую виконання, але це просто працює назавжди. Не впевнений, у чому проблема


Де і як визначається _numRetries?
Натан А

Його в області класу і ініціалізовано з 0 в конструкторі. AnalyzeSingle () - це єдине місце, де я його використовую.
Шерман Шето

Ви працюєте в режимі налагодження? Оптимізована проблема може бути через те, що ви працюєте в режимі випуску.
Натан А

Зараз я перебуваю на Debug / iisExpress
Sherman

Відповіді:


176

Те, як ви користуєтеся функцією очікування / асинхронізації, в кращому випадку поганий, і це ускладнює його дотримання. Ви змішуєте awaitз Task'1.Result, яка тільки збиває з пантелику. Однак, схоже, ви дивитесь на кінцевий результат, а не на зміст.

Я переписав ваш виклик функції та функції, який повинен вирішити вашу проблему:

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

І ваш остаточний дзвінок функції:

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

Або ще краще:

var finalResult = await GetResponseString(text);

Дякую!! Я намагався зрозуміти, як працює асинхроніка / очікування протягом останніх кількох годин (MSDN + stackoverflow), але я, очевидно, ще не зрозумів її повністю. Чи є ресурси, які Ви б запропонували?
Шерман Шето

1
Просто продовжуйте грати з ним, і ви зрештою отримаєте повісити його. Це велика концепція, щоб зрозуміти все відразу.
Натан

У мене все ще виникають проблеми. Я оновив свою проблему в оригінальній публікації. Проблема може полягати в тому, що я кодую для синхронного виконання, але я не впевнений, як вирішити цю проблему
Sherman Szeto

1
HttpClient реалізує IDisposable, тому краще обернути його у використовуваному операторі.
Пайям

2
@Payam, хоча це правда, що він реалізує, IDisposableви не повинні загортати його у usingзаяві. Це рідкісний виняток із правила. Дивіться цю публікацію для отримання додаткової інформації: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty

62

Якщо ви не хочете використовувати, asyncви можете додати, .Resultщоб змусити код виконувати синхронно:

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 додає .Результат до вашого PostAsync робить його неасистемним
Майк

6
@Mike - це не те, що говорить nbushnell? :-)
PoeHaH

Для чого тип response? У мене є аналогічний код, але мені потрібно зробити responseглобальним, тому мені потрібен тип. Дякую.
Azurespot

1
@AzureSpot: Тип відповіді - HttpResponseMessage.
RWC
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.