【问题标题】:HttpResponseMessage to stringHttpResponseMessage 到字符串
【发布时间】:2019-12-03 10:23:18
【问题描述】:

我正在调用一个返回Task的方法,在调用方法中我需要读取字符串形式的响应。

这是我放的代码:

static public async Task<HttpResponseMessage> Validate(string baseUri,HttpContent content) {
    HttpResponseMessage response = new HttpResponseMessage();   
    response = await client.PostAsync(baseUri,content);    
    return response;
}

public string test(){
    string postJson = "{Login = \"user\", Password =  \"pwd\"}";
    HttpContent stringContent = new StringContent(postJson, 
    UnicodeEncoding.UTF8, "application/json");
    HttpResponseMessage result=Validate(Uri,stringContent);
    var json = result.Content.ReadAsStringAsync().Result;
}

我期望字符串,但抛出此错误:

Cannot implicitly convert type 
'System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>' to 
'System.Net.Http.HttpResponseMessage'

【问题讨论】:

  • 试试 HttpResponseMessage result=Validate(Uri,stringContent).Result;
  • @auburg:以这种方式阻止可能cause a deadlock
  • 在这种情况下,OP 需要等待对 Validate 的调用

标签: c#


【解决方案1】:

您的问题出在:

HttpResponseMessage result=Validate(Uri,stringContent);

Validate 正在返回一个任务,而不是 HttpResponseMessage

将其更改为:

var result = Validate(Uri,stringContent).Result;

只是稍微清理一下代码并避免使用Result,如果你有能力改变它:

static public async Task<HttpResponseMessage> Validate(string baseUri, HttpContent content)
{  
   return await client.PostAsync(baseUri,content);
}

public async Task<string> test()
{
   var postJson = "{Login = \"user\", Password =  \"pwd\"}";
   var stringContent = new StringContent(postJson, UnicodeEncoding.UTF8, "application/json");
   var result = await Validate(Uri,stringContent);
   return await result.Content.ReadAsStringAsync();
}

与您的编码风格保持一致。至于为什么调用 .Result 不好,正如人们在 cmets 中指出的那样,请查看 this blog

【讨论】:

  • 调用 .Result 很糟糕,因为可能会出现锁。
  • 是的,但这是一个完全不同的问题。重新设计他的代码不是我的责任:)
  • @swdon:但您可以在答案中反映出来。请记住,SO 不仅是直接向 OP 提供的知识来源,也是对今年以后访问的其他人的知识来源。那时肯定可以改进一个暗示可能是不好的方法的答案。
  • 返回等待结果.Content.ReadAsStringAsync(); - 我可以把它转换成纯字符串吗?
  • return result.Content.ReadAsStringAsync().Result
【解决方案2】:

方法Validate返回任务并且是异步的。基本上你可以通过两种不同的方式调用这个方法:

1) 在另一个异步方法中等待Validate 的结果,像这样...

public async Task<string> test() {
    string postJson = "{Login = \"user\", Password =  \"pwd\"}";
    HttpContent stringContent = new StringContent(postJson, 
        UnicodeEncoding.UTF8, "application/json");
    HttpResponseMessage result = await Validate(Uri,stringContent);
    var json = result.Content.ReadAsStringAsync().Result;
}

2) 在等待这个结果时阻塞当前执行,像这样...

public string test() {
    string postJson = "{Login = \"user\", Password =  \"pwd\"}";
    HttpContent stringContent = new StringContent(postJson, 
        UnicodeEncoding.UTF8, "application/json");
    HttpResponseMessage result = Validate(Uri,stringContent).Result;
    var json = result.Content.ReadAsStringAsync().Result;
}

除非你真的有阻塞调用线程的冲动,否则默认选择第一种方式。

请注意,在 WinForms、WPF 或 ASP.NET 应用程序中使用第二种解决方案时,您可能会遇到死锁。像这样修改Validate方法应该可以解决问题:

response = await client.PostAsync(baseUri,content).ConfigureAwait(false);

【讨论】:

    【解决方案3】:
    1. 为了便于阅读,将方法名称从 Validate(..) 更改为 ValidateAsync(..)。只是为了说明这个方法返回一个任务,你必须等待它。

    2. 调用 Validate 方法时缺少等待。如果你不想或不能让调用者异步,那么使用方法GetAwaiter().GetResult(),你会得到你想要的。

    3. ReadAsStringAsync().Result 替换为ReadAsStringAsync().GetAwaiter().GetResult()

    就像其他人在 cmets 中写的那样,调用 .Result 很糟糕,因为它可能导致锁定。这同样适用于GetAwaiter().GetResult(),但调用它们优于调用Result。最好的选择是使用await/async

    如果您想知道GetAwaiter().GetResult() 与调用Result 之间的区别是什么,您可以阅读以下内容: Is Task.Result the same as .GetAwaiter.GetResult()?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-23
      相关资源
      最近更新 更多