假设我有一个由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;
}
在第一行,当我调用Client.GetAsync
时,我调用了我的API。在我的API中,我可以正确地接收到调用,并且可以通过User对象正确返回Ok,或者返回其他代码。有用。我的API有效。但是然后什么都没有。我的客户永远不会继续。似乎Client.GetSync
正在等待。我从不进行下一步评估状态代码。
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;
}
没有等待的相同代码我没有问题。我的代码一直运行到下一步。证明我的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
答案 0 :(得分:5)
我只是在Sub之前添加了Async单词,并更改了_authService.Login(用户名,密码)。结果由await _authService.Login(用户名,密码)
一般指南为"Don't block on async code"。这是asynchronous programming best practices之一。
阻塞异步代码是不好的,因为默认情况下await
works by capturing a "context"会在这种情况下恢复执行async
方法。 UI上下文是一种上下文,它使async
方法在UI线程上恢复执行。
因此,您看到的死锁是由阻塞UI线程引起的。代码先调用async
方法,然后阻塞UI线程,直到完成async
方法。但是,该await
方法中的async
捕获了UI上下文,因此它等待UI线程空闲才可以完成。 UI线程正在等待async
方法,而async
方法正在等待UI线程:死锁。
您的修正工作的原因是,不再等待async
方法阻止UI线程,因此不再有死锁。