如何从HttpClient调用中获取内容主体?

162

我一直在尝试弄清楚如何读取httpclient调用的内容,但我似乎无法做到。我得到的响应状态是200,但我无法找出如何获取实际返回的Json,这就是我需要的全部内容!

以下是我的代码:

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

这是我得到的结果:

响应 Id = 89,状态 = RanToCompletion,方法 = "{null}",结果 = "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>

更新:这是根据Nathan的回复修改后的代码

    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 = 无法计算表达式,因为当前方法的代码已经被优化了。, Status = 无法计算表达式,因为当前方法的代码已经被优化了。, Method = 无法计算表达式,因为当前方法的代码已经被优化了。, Result = 无法计算表达式,因为当前方法的代码已经被优化了。

继续执行,但它仍然永远运行。 不确定问题出在哪里。


_numRetries 是在哪里和如何定义的? - Nathan A
它在类的范围内,并在构造函数中初始化为0。AnalyzeSingle()是我唯一使用它的地方。 - Sherman Szeto
你是在调试模式下运行吗?优化问题可能是因为你正在运行发布模式。 - Nathan A
我目前正在调试/iisExpress。 - Sherman Szeto
2个回答

248

你使用await/async的方式很糟糕,难以理解。你混合了awaitTask'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);

1
谢谢!我已经花了几个小时(在MSDN和stackoverflow上)尝试理解异步/等待的工作原理,但显然我还没有完全掌握。你有什么资源可以推荐吗? - Sherman Szeto
3
继续尝试操作,最终你就会掌握它。这是一个需要逐渐理解的大概念。 - Nathan A
2
HttpClient 实现了 IDisposable 接口,因此最好将其包装在 using 语句中。 - Payam
7
@Payam,虽然它实现了IDisposable接口,但你不应该用using语句来封装它。这是一个罕见的例外。请参考这篇文章获取更多信息:https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/。 - maxshuty
感谢 @NathanA,它实际上返回了JSON。最终我将返回值更改为类对象,而不是字符串。感谢您建议对其进行序列化,应该可以奏效。 - cvillalobosm
显示剩余3条评论

87

如果您不想使用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;
 }  

4
在调用 PostAsync 方法时添加 .Result 会使它变成同步阻塞的方法,但不会改变原本的意思。 - Mike
13
@Mike,nbushnell 不就是在说这个吗? :-) - PoeHaH
response 的类型是什么?我有类似的代码,但我需要将 response 声明为全局变量,因此我需要知道它的类型。谢谢。 - Azurespot
1
@AzureSpot:响应的类型是HttpResponseMessage。 - RWC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接