【发布时间】:2019-03-01 00:09:41
【问题描述】:
假设我有一个由 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 中,我正确地收到了调用,并且我正确地返回了带有我的用户对象的 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;
}
没有等待的相同代码我没有问题。我的代码运行到下一步。证明我的 API 不是问题。
很明显,这是与等待/异步有关的问题。我必须做错什么,但怎么办?你能帮助我吗?和调试器有关系吗?
更多信息这里是我之前的代码图片
在我点击下一步之后。请注意,我的调用堆栈为空,代码仍在运行。
这里要求的是我调用登录的代码。我刚刚在 Sub 之前添加了 Async 字,并通过 await _authService.Login(username, password) 更改了 _authService.Login(username, password).Result
我现在工作。
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
【问题讨论】:
-
Same code without the await I have no problem相反,你有一个大问题。您阻塞了等待异步操作的线程。这意味着您阻止了桌面应用程序上的 UI 线程或阻止了可以在 Web 应用程序中为另一个请求提供服务的线程。块以 spinwaits 开头,这意味着您在不做任何事情的情况下固定 CPU。在服务器应用程序中,这不仅会降低吞吐量,还会增加 CPU 利用率,并可能导致应用程序池在高负载下回收 -
如果您遇到问题,请调试您的代码,添加适当的异常处理并找出问题所在。也许另一台服务器从未响应。也许有一个没有被捕获的异常。或者结果可能无法反序列化为
UserDto -
我点击 F10 进入下一步然后什么也没有发生。我可以永远等待,什么都不会发生。
-
HttpClient.GetAsync有效。await有效。如果您的代码阻塞,您必须查看代码中发生了什么。也许还没有回应。也许您有一个桌面应用程序并在顶部阻止 UI 线程,阻止await返回到它。您可以使用例如var task=Login(...);MessageBox.ShowDialog(..);, await task;轻松做到这一点。删除await或添加.Result并不能证明什么。没有实际代码,不知道发生了什么,只能猜测 -
通过在我的 ButtonLogin 事件处理程序中添加 Async 并在调用登录之前等待,我可以解决此问题。
标签: c# async-await