了解HttpClient请求期间的异步等待指令

Bas*_*mme 2 c# async-await

假设我有一个由2个项目组成的解决方案。一个旧的WinForm经典项目。在这个旧项目中,我有一个登录窗口。单击此登录窗口的“确定”后,我将启动一个事件,该事件将调用REST API。两个应用程序均在调试模式下同时启动。

在我的代码中的某个地方,我有以下代码:

public async Task<User> Login(string username, string password)
{
    HttpResponseMessage response = await Client.GetAsync($"api/Login?login={username}&password={password}");
    if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
        return new User();
    response.EnsureSuccessStatusCode();
    var userDto = await response.Content.ReadAsAsync<UserDto>();
    var user = userDto.ToUser();
    return user;
}
Run Code Online (Sandbox Code Playgroud)

在调用的第一行中,我调用了Client.GetAsync我的API。在我的API中,我可以正确地接收到调用,并且可以通过User对象正确返回Ok,或者返回其他代码。有用。我的API有效。但是然后什么都没有。我的客户永远不会继续。似乎正在Client.GetSync等待。我从不进行评估StatusCode的下一步。

public async Task<User> Login(string username, string password)
{
    HttpResponseMessage response = Client.GetAsync($"api/Login?login={username}&password={password}").Result;
    if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
        return new User();
    response.EnsureSuccessStatusCode();
    var userDto = await response.Content.ReadAsAsync<UserDto>();
    var user = userDto.ToUser();
    return user;
}
Run Code Online (Sandbox Code Playgroud)

没有等待的相同代码我没有问题。我的代码一直运行到下一步。证明我的API不是问题。

很明显,这是与等待/异步相关的问题。我必须做错什么,但是呢?你能帮助我吗?与调试器有关吗?

有关更多信息,这里是我的代码之前的图片

在此处输入图片说明

然后单击下一步。请注意,我的调用堆栈为空,并且代码仍在运行。

在此处输入图片说明

根据要求,这里是我称为登录名的代码。我只是在Sub之前添加了异步字,并更改了_authService.Login(用户名,密码)。结果由await _authService.Login(用户名,密码)

我现在上班

Private Async Sub ButLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butLogin.Click
    DataProxies.SetToken()
    Dim _authService As IAuthenticationService = New AuthenticationService()


    Dim username As String = txtLogin.Text
    Dim password As SecureString = New NetworkCredential(String.Empty, txtPwd.Text).SecurePassword

    Dim auth As Tuple(Of Boolean, User) = Await _authService.Login(username, password)
    If (auth.Item1) Then
        Dim user As User = auth.Item2
        Name = $"{user.FirstName} {user.LastName}"
        ApiInformations.ApiToken = user.SessionToken
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 5

我只是在Sub之前添加了异步字,并更改了_authService.Login(用户名,密码)。结果由await _authService.Login(用户名,密码)

一般指导是“不要阻止异步代码”。这是异步编程的最佳实践之一

阻塞异步代码是不好的,因为默认情况下,它await通过捕获“上下文”来工作,并async在该上下文中恢复执行该方法。UI上下文是一种上下文,它使async方法恢复在UI线程上执行。

因此,您看到的死锁是由阻塞UI线程引起的。代码先调用该async方法,然后阻塞UI线程,直到该async方法完成。然而,await在该async方法中捕获的UI背景,所以它正在等待UI线程是免费的,才能够完成。UI线程正在等待async方法,而该async方法正在等待UI线程:死锁。

您的修复工作成功的原因是,不再等待该async方法阻止UI线程,因此不再有死锁。