如何从异步任务<>获取结果什么时候我不能Run()?

时间:2017-08-02 09:03:43

标签: c# asp.net asynchronous

我正在尝试通过Asynctask使用POST方法调用另一个API。 一切正常(请求正确执行,因为它启动我的SQL请求)但我无法从外部服务器获得任何响应。

我可以看到我不需要运行任务来使其执行但我没有任何结果。

    [HttpPost]
    public string Post([FromBody]JObject value)
    {
        if (MesureController.CheckJsonIntegrity<Mesure>(value))
        {
            var task = MesureAsync(value);
            return task.Result;
        }
        return null;
    }

    static async Task<string> MesureAsync(JObject value)
    {
        using (client)
        {
            string url = ConfigurationManager.AppSettings["internalserver:url"];
            var json_string = new Dictionary<string, string>
            {
                {"json_string", value.ToString() }
            };
            var content = new FormUrlEncodedContent(json_string);
            var response = await client.PostAsync(url + "Mesure/Index", content);
            string resultContent = await response.Content.ReadAsStringAsync();
            return resultContent;
        }
    }

3 个答案:

答案 0 :(得分:1)

您看到了common deadlock that I describe in more detail on my blog。总之,ASP.NET(完整的,而非Core)代码在&#34;请求上下文中运行&#34;只允许一个线程一次处理一个请求。当MesureAsync将POST发送到其他API时,它returns an incomplete task。然后,您的Post方法会阻塞当前线程,等待该任务。稍后,当对其他API的POST完成时,MeasureAsync会尝试继续执行within that same request context,但它不能,因为Post已阻止该请求上下文中的某个线程,并且请求上下文一次只允许一个线程。

因此,您最终会Post占用请求上下文,等待MeasureAsync完成,MeasureAsync等待Post放弃请求上下文,以便它可以完成。经典僵局。

最佳解决方案是"async all the way",即不要阻止异步代码。在这种情况下,请将Result替换为await

[HttpPost]
public string Post([FromBody]JObject value)
{
  if (MesureController.CheckJsonIntegrity<Mesure>(value))
  {
    return await MesureAsync(value);
  }
  return null;
}

如果您现在尝试编译它,它会给您一个编译器错误,告诉您如何处理Post以使其工作:

[HttpPost]
public async Task<string> Post([FromBody]JObject value)
{
  if (MesureController.CheckJsonIntegrity<Mesure>(value))
  {
    return await MesureAsync(value);
  }
  return null;
}

......你已经完成了!

答案 1 :(得分:0)

由于阻塞和异步代码的混合,原始代码中没有返回结果。

应该将actions语法更新为异步,并允许更好的内容协商。

假设此代码适用于Asp.Net-Core,则操作将更新为

[HttpPost]
public async Task<IActionResult> Post([FromBody]JObject value) {
    if (MesureController.CheckJsonIntegrity<Mesure>(value)) {
        var measure = await MesureAsync(value);
        return Ok(measure);
    }
    return BadRequest();
}

如果使用WebAPI 2. *然后将IActionResult更改为IHttpActionResult,它将以相同的方式工作。

答案 2 :(得分:-1)

您必须确保Task将会运行。

使用此代码段:

Task.Run(()=>MesureAsync(value)).Result;

相关问题