Понимание инструкции асинхронного ожидания во время запроса HttpClient

2

Допустим, у меня есть решение, состоящее из 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. Я должен сделать что-то не так, но что? Вы можете мне помочь? Это связано с отладчиком?

Для получения дополнительной информации здесь изображение моего кода, прежде чем

Изображение 174551

И после того, как я нажму на следующий шаг. Обратите внимание, что мой стек вызовов пуст, а код все еще выполняется.

Изображение 174551

Как и было запрошено, здесь указан код, по которому я называю логин. Я просто добавил асинхронное слово перед 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
  • 1
    Same code without the await I have no problem наоборот, у вас есть большие проблемы. Вы заблокировали поток, ожидающий асинхронную операцию. Это означает, что вы заблокировали поток пользовательского интерфейса в настольном приложении или заблокировали поток, который может обслуживать другой запрос в веб-приложении. Блоки начинаются с spinwaits, что означает, что вы привязываете процессор, ничего не делая. В серверном приложении это не только снижает пропускную способность, но и увеличивает загрузку ЦП и может привести к перезагрузке пула приложений при большой нагрузке.
  • 0
    Если у вас есть проблема, отладьте ваш код, добавьте правильную обработку исключений и выясните, в чем дело. Возможно, другой сервер никогда не отвечал. Возможно, было исключение, которое не было поймано. Или, возможно, результат не может быть десериализован в UserDto
Показать ещё 11 комментариев
Теги:
async-await

1 ответ

5
Лучший ответ

Я просто добавил асинхронное слово перед Sub и изменил _authService.Login (имя пользователя, пароль). Результат с помощью await _authService.Login (имя пользователя, пароль)

Общее руководство: "Не блокировать асинхронный код". Это один из лучших методов асинхронного программирования.

Блокировка асинхронного кода является плохой, потому что await работает, захватывая "контекст" по умолчанию, и возобновляет выполнение async метода в этом контексте. Одним контекстом является контекст пользовательского интерфейса, который заставляет async метод возобновить выполнение в потоке пользовательского интерфейса.

Таким образом, тупик, который вы видели, был вызван блокировкой потока пользовательского интерфейса. Код вызывал async метод, а затем блокировал поток пользовательского интерфейса, пока этот async метод не завершился. Тем не менее, await в этом async методе захватил контекст пользовательского интерфейса, поэтому он ждет поток пользовательского интерфейса, чтобы быть свободным, прежде чем он сможет завершить. Поток пользовательского интерфейса ожидал async метод, а async метод ожидал поток пользовательского интерфейса: взаимоблокировка.

Причина, по которой ваше исправление сработало, заключается в том, что поток пользовательского интерфейса больше не блокируется в ожидании async метода, поэтому больше нет тупиков.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню