Допустим, у меня есть решение, состоящее из 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 с моим объектом User, или я возвращаю другой код. Оно работает. Мой 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 не проблема.
Это ясно, что это проблема, связанная с await/async. Я должен сделать что-то не так, но что? Вы можете мне помочь? Это связано с отладчиком?
Для получения дополнительной информации здесь изображение моего кода, прежде чем
И после того, как я нажму на следующий шаг. Обратите внимание, что мой стек вызовов пуст, а код все еще выполняется.
Как и было запрошено, здесь указан код, по которому я называю логин. Я просто добавил асинхронное слово перед 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
Я просто добавил асинхронное слово перед Sub и изменил _authService.Login (имя пользователя, пароль). Результат с помощью await _authService.Login (имя пользователя, пароль)
Общее руководство: "Не блокировать асинхронный код". Это один из лучших методов асинхронного программирования.
Блокировка асинхронного кода является плохой, потому что await
работает, захватывая "контекст" по умолчанию, и возобновляет выполнение async
метода в этом контексте. Одним контекстом является контекст пользовательского интерфейса, который заставляет async
метод возобновить выполнение в потоке пользовательского интерфейса.
Таким образом, тупик, который вы видели, был вызван блокировкой потока пользовательского интерфейса. Код вызывал async
метод, а затем блокировал поток пользовательского интерфейса, пока этот async
метод не завершился. Тем не менее, await
в этом async
методе захватил контекст пользовательского интерфейса, поэтому он ждет поток пользовательского интерфейса, чтобы быть свободным, прежде чем он сможет завершить. Поток пользовательского интерфейса ожидал async
метод, а async
метод ожидал поток пользовательского интерфейса: взаимоблокировка.
Причина, по которой ваше исправление сработало, заключается в том, что поток пользовательского интерфейса больше не блокируется в ожидании async
метода, поэтому больше нет тупиков.
Same code without the await I have no problem
наоборот, у вас есть большие проблемы. Вы заблокировали поток, ожидающий асинхронную операцию. Это означает, что вы заблокировали поток пользовательского интерфейса в настольном приложении или заблокировали поток, который может обслуживать другой запрос в веб-приложении. Блоки начинаются с spinwaits, что означает, что вы привязываете процессор, ничего не делая. В серверном приложении это не только снижает пропускную способность, но и увеличивает загрузку ЦП и может привести к перезагрузке пула приложений при большой нагрузке.UserDto