【问题标题】:HttpClient PostAsync() never return responseHttpClient PostAsync() 从不返回响应
【发布时间】:2015-12-03 23:32:27
【问题描述】:

我的问题与这里的question 非常相似。我有一个 AuthenticationService 类,它生成一个 HttpClient PostAsync() 并且当我从 ASP 项目运行它时从不返回结果,但是当我在控制台应用程序中实现它时它工作得很好。

这是我的身份验证服务类:

public class AuthenticationService : BaseService
{
    public async Task<Token> Authenticate (User user, string url)
    {
        string json = JsonConvert.SerializeObject(user);
        StringContent content = new StringContent(json, Encoding.UTF8, "application/json");

        HttpResponseMessage response = await _client.PostAsync(url, content);
        string responseContent = await response.Content.ReadAsStringAsync();
        Token token = JsonConvert.DeserializeObject<Token>(responseContent);

        return token;
    }
}

它挂在这里:HttpResponseMessage response = await _client.PostAsync(url, content);

这是我的控制器调用服务:

public ActionResult Signin(User user)
{
    // no token needed to be send - we are requesting one
    Token token =  _authenticationService.Authenticate(user, ApiUrls.Signin).Result;
    return View();
}

这是我如何使用控制台应用程序测试服务的示例,它运行良好。

class Program
{
    static void Main()
    {
        AuthenticationService auth = new AuthenticationService();

        User u = new User()
        {
            email = "email@hotmail.com",
            password = "password123"
        };

        Token newToken = auth.Authenticate(u, ApiUrls.Signin).Result;

        Console.Write("Content: " + newToken.user._id);
        Console.Read();
    }
}

【问题讨论】:

    标签: c# asp.net asynchronous httpclient


    【解决方案1】:

    由于您使用的是.Result,这最终会导致您的代码出现死锁。这在控制台应用程序中工作的原因是因为控制台应用程序没有上下文,但 ASP.NET 应用程序有(请参阅Stephen Cleary's Don't Block on Async Code)。你应该在你的控制器asyncawait 中调用Signin 方法来调用_authenticationService.Authenticate 来解决死锁问题。

    【讨论】:

      【解决方案2】:

      由于您使用的是.Result.Waitawait,这最终会在您的代码中导致死锁

      您可以在async 方法中使用ConfigureAwait(false)防止死锁

      像这样:

      string responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
      

      您可以尽可能使用ConfigureAwait(false) 来表示不要阻塞异步代码。

      【讨论】:

      • ConfigureAwait 可以防止死锁。然而,这并不是真正的意图,并且存在副作用(特别是在网站中,您可能无法访问来自 HttpContext 的信息)。最好在使用 ConfigureAwait 之前对其进行深入研究。
      • 您在上面引用的源代码还说:“使用 ConfigureAwait(false) 来避免死锁是一种危险的做法。在所有方法的传递闭包中,您必须对每个 await 使用 ConfigureAwait(false)由阻塞代码调用,包括所有第三方和第二方代码。使用 ConfigureAwait(false) 避免死锁充其量只是一种 hack)。"
      • msdn.microsoft.com/en-us/magazine/jj991977.aspx 这篇文章很好地解释了何时应该使用 ConfigureAwait 以及需要注意什么。
      【解决方案3】:

      如果有人来需要查看代码,我只需将控制器更改为如下所示:

          /***
          *** Added async and Task<ActionResult>
          ****/
          public async Task<ActionResult> Signin(User user)
          {
              //no token needed - we are requesting one
              // added await and remove .Result()
              Token token =  await _authenticationService.Authenticate(user, ApiUrls.Signin);
      
              return RedirectToAction("Index", "Dashboard", token.user);
          }
      

      感谢大家的快速回复!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多