Блокируется с помощью асинхронного - не стандартный тупик - PullRequest
0 голосов
/ 24 мая 2018

Я называю асинхронные методы и что-то тупиковое.Теперь я понятия не имею, почему это происходит.Я не думаю, что это стандартная тупиковая ситуация, потому что я вызываю Task.Result в методе Main, а не в потоке пользовательского интерфейса.Более того, я также попытался использовать асинхронную Main без каких-либо вызовов Task.Но результат тот же.

Проблема с проектом WinForms.Все начинается в методе Main:

bool res = Task.Run(() => contr.RegisterPremiseAllInOne()).Result;

Это реализованный вызов асинхронного метода RegisterPremiseAllInOne в новой задаче.

Что происходит дальше ... RegisterPremiseAllInOne работает примерно так (упрощенная модель):

public async Task<bool> RegisterPremiseAllInOne()
{
   AppUser loggedAppUser = await appUserContr.GetLoggedAppUser(); // <-- everything works fine here
   if(loggedAppUser == null)
      return false;

   var premises = await GetPremisesForLoggedUser(); //at the end there is a deadlock
}

Теперь я покажу вам, какие вызовы выполняет каждый метод (все заканчивается запросами остальных в WebApi):

GetLoggedAppUser -> 
await API.Users.GetLoggedAppUser() -> 
await ClientHelper.GetObjectFromRequest<Appuser>("AppUsers/logged") -> 
await SendAsyncRequest() -> 
await HttpClient.SendAsync()

Надеюсь, это вполне читабельно.

Этот путь работает хорошо.Что интересно, GetPremisesForLoggedUser частично сходится с GetLoggedAppUser и выглядит так:

GetPremisesForLoggedUser -> 
await API.Premises.GetForLoggedUser() -> 
await ClientHelper.GetListFromRequest<premise>("premises/logged") -> 
await SendAsyncRequest() -> 
await HttpClient.SendAsync()

Как видите, есть прямой путь.Позвоните в API и, в конечном итоге, отправьте http-запрос.

Deadlock находится в пределах SendAsync с HttpClient.Я понятия не имею, почему.И все же первый путь работает нормально.

На стороне сервера все тоже хорошо.Сервер возвращает успешный ответ.Но клиент зависает.

Я думаю, что это должно работать.Я не смешиваю синхронно с асинхронным кодом.Все методы возвращают Task<T> и помечаются как асинхронные.

Может быть, кто-то знает, где может существовать проблема?Может быть, вы захотите увидеть некоторые скриншоты из окон отладки: Parallel Stack / Tasks?

1 Ответ

0 голосов
/ 24 мая 2018

ОК, благодаря @usr и @Evk я нашел ошибку.Однако это был стандартный тупик пользовательского интерфейса, но немного более замаскированный.

Непосредственно перед вызовом GetPremisesForLoggedUser() Я СОЗДАВАЛ форму, используя фабрику (контейнер IoC):

IPremisePickerView view = objFactory.Resolve<IPremisePickerView>();
var premises = await GetPremisesForLoggedUser();

Когда формасозданный поток, которому принадлежит эта форма, автоматически становится потоком пользовательского интерфейса.Я думаю, это сделано в классе Form.

Получается, что я вызывал await GetPremisesForLoggedUser ()

в потоке пользовательского интерфейса.Поэтому, вероятно, все задачи начали выполняться в потоке пользовательского интерфейса (с некоторой точки).Но значит ли это, что Task.Run.Result, вызываемый в Main, блокировал поток пользовательского интерфейса в ожидании результата?Я не уверен, потому что это было вызвано в главном потоке (в этом случае НЕ поток пользовательского интерфейса).Поэтому, если бы кто-то мог придумать мой ответ, было бы неплохо.

В любом случае, после перемещения создания формы ниже вызова асинхронного метода все начало работать.

...