c# - asyncawait确实等了很多

标签 c# asp.net-mvc-4 async-await

public class GeoHelper
{ 
    const string GeoIpUrl = "http://freegeoip.net/json/{0}";
    private readonly string _ipAddress = string.Empty;

    public GeoHelper(string ip)
    {
        _ipAddress = ip;
    }

    public async Task<string> GetGeoAsync()
    {
        string uri = string.Format(GeoIpUrl, _ipAddress);

        var httpClient = new HttpClient();

        var response = await httpClient.GetAsync(uri);

        response.EnsureSuccessStatusCode();

        var content = await response.Content.ReadAsStringAsync();

        return content;
    }

}

然后我这样调用它:

    [ChildActionOnly]
    public ActionResult UserGeo()
    {
        var ip = RequestHelper.GetClientIpAddress(Request);

        var geoHelper = new GeoHelper(ip);

        var response = geoHelper.GetGeoAsync();

        var result = response.Result;

        var resultobj = JsonConvert.DeserializeObject<GeoInfo>(result);

        return Content(resultobj.city);
    }

var result = response.Result;它等待并且永远不会结束,我在等待时头发花白。我有一个小型控制台应用程序,它在那里工作得很好。相同的代码。

为什么?我该如何修复?

最佳答案

不幸的是,MVC 目前不支持异步子操作。请对此问题投票( CodePlexUserVoice )。

我解释一下死锁问题on my blog 。本质上,这是因为 ASP.NET 在请求上下文中一次只允许一个线程,当您在请求上下文中阻止一个线程(使用 Result)时,任何 async 尝试重新进入该上下文的方法无法完成。

您可以使用各种技巧,但最干净的解决方案是如果可以的话只使用同步代码。另一种解决方案是使用 Result,但在这种情况下,您必须确保 GetGeoAsync 中的每个 await (以及每个 async code> 方法调用)使用 ConfigureAwait(false),这意味着您不能使用 HttpContext、请求或响应。​​

第三种解决方案相当hacky,是使用我的AsyncEx library中的AsyncContext.Run :

[ChildActionOnly]
public ActionResult UserGeo()
{
  return AsyncContext.Run(async () =>
  {
    var ip = RequestHelper.GetClientIpAddress(Request);
    var geoHelper = new GeoHelper(ip);
    var response = geoHelper.GetGeoAsync();
    var result = await response;
    var resultobj = JsonConvert.DeserializeObject<GeoInfo>(result);
    return Content(resultobj.city);
  }
}

但是,AsyncContext 方法并不适用于所有代码。它设置了一种“嵌套循环”,但不使用 AspNetSynchronizationContext,因此某些 ASP.NET 代码不喜欢在 AsyncContext 中运行。

关于c# - asyncawait确实等了很多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18672612/

相关文章:

c# - 将 IEnumerable ViewModel 传递给 View

javascript - 如何从附加到 Puppeteer 页面的 pageerror 监听器捕获错误?

javascript - 在异步函数之外使用 await

c# - 子列表的补充列表

c# - 如何在 MVVM-WPF 中获取选定的项目

C# 正则表达式 - 替换为自身

azure - Windows Azure 角色间通信

c# - OpenQA.Selenium.DriverServiceNotFoundException

asp.net - 更新到 Asp.Net MVC 4 RTM 后无法加载类型 HttpControllerConfigurationAttribute

c# - authContext.AcquireTokenByAuthorizationCode 不适用于最新的 System.IdentityModel.Clients.ActiveDirectory