2015-07-28 1 views
2

Я делаю некоторую OAuth работу, где я получаю свой токен обновления через метод при условии асинхронной API (GetRefreshTokenAsync):Получения асинхронного результата запирания (несмотря на настройки Configure ждет ложь)

public async Task<Tokens> RenewAuthentication() 
{ 
    AppTokenResult token = await OAuth.GetRefreshTokenAsync("clientid", 
     "clientsecret", 
    @"myRefreshToken"); 

    string accessToken = token.AccessToken; 
    string refreshToken = token.RefreshToken; 

    return new Tokens(accessToken, refreshToken); 

} 

Если я называю это как от метода, не асинхронном как таковой:

public void noAsync() 
{ 
    var r = RenewAuthentication(); 
    var x = r.Result; 
} 

это ТУПИКИ приложение :(Если удалить 2-ой линии (r.Result), то это работает, но это дерьмо, потому что я не могу получить. Я попытался прочитать

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Но, попробовав свой метод 1, добавив в метод GetRefreshTokenAsync() методConfigureAwait (false), это не имело никакого значения.

Любые советы?

+0

Итак, пользовательский интерфейс должен работать, пока результат не получен? – Thulur

+0

Какая платформа работает? Консоль, WPF, iOS, ASP.NET ...? И почему вы вызываете метод async из синхронизации?Рекомендация - использовать async от начала до конца. – Krumelur

+0

Пользовательский интерфейс может работать или не работать во время получения результата. Хотя я бы предпочел, чтобы пользовательский интерфейс был заблокирован, это не настоящая проблема, верно? Проблема в том, что все дело в тупике. Работает на WinForms. Я вызываю async из загрузки формы. Когда форма сначала загружается, я хочу и дать пользователю OAuth, чтобы я мог хранить свои жетоны. – Prof

ответ

5

It ТУПИКИ приложение :(

Вот что блокирование на async метода в среде, которая имеет пользовательский синхронизация будет делать.

Если вы называете это на «FormLoad», вы . не нужно блокировать Просто заметь обработчик события как async, так что вы можете await на операции:

public Form() 
{ 
    this.Load += OnLoadHandler; 
} 

public async void OnLoadHandler(object sender, EventArgs e) 
{ 
    var result = await RenewAuthenticationAsync(); 
    // Store the result here 
} 
+0

да, это будет работать, но Мне посчастливилось быть в рамках события, которое я мог бы добавить к асинхронному отборочному. что произойдет, если я захочу назвать это из основной функции? – Prof

+0

Вы бы назвали метод асинхронного метода «огнем и забыли». Вы должны уйти от идеи блокировки асинхронных операций. – Krumelur

+0

Тогда вы были бы ввернуты. 'async' имеет тенденцию расти в вашем приложении и имеет собственную кодовую базу. Естественно, вы не можете смешивать синхронные и асинхронные методы, которые не работают. Единственная альтернатива, которую у вас есть, это «async void», которая ужасна и определенно не должна использоваться. Вы можете проектировать свое приложение, чтобы оно могло обойти это. Если это невозможно, вы всегда можете использовать синхронные API. Выполнение 'async' в основном принесет пользу, если вы ищете масштабируемость. Если это не проблема, синхронизация будет прекрасной. –

1

Если вы получаете доступ к свойству Result задачи, он будет действовать как Future, и он заблокирует текущий поток, пока задача не вернется с результатом.

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

Убедитесь, что ваш звонок в OAuth.GetRefreshTokenAsync возвращается.

+0

он вернется, если я удалю .Result. Если я остановлюсь на строковых присвоениях внутри RenewAuthentication, они попадают, когда я НЕ использую .Result(). когда я добавляю .Result, GetRefreshTokenAsync никогда не возвращается (заканчивается). Что я могу сделать? – Prof

+0

Конечно, ты прав. Вызов GetRefreshTokenAsync, очевидно, ожидает тот же поток, который ожидает результат вашей задачи. Итак, вы правы ... тупик. Чтобы решить эту проблему, вам нужно ждать результата вашей задачи в отдельной задаче. Так что если вы замените 'вар х = r.Result' по ' Task.Run (() => { вара х = r.Result; // сделать что-то с й здесь }); ' все должно работать как и ожидалось. – Norbert

-1

async код весь путь конструкция. Вы не можете выполнить половину асинхронного действия и не должны пытаться его принудительно. noAsync, кажется, ничего полезного здесь не делает.

В своей мудрости г-н Клири дает понять, что каждый метод async имеет свой собственный контекст, в котором он может продолжать продолжение в пользовательском интерфейсе.

Вы уверены, что OAuth.GetRefreshTokenAsync использует ConfigureAwait(false) внутренне? Если это не так, вы зашли в тупик.

+0

Я не могу быть уверен, что GetFreshTokenAsync использует ConfigureAwait (false) внутренне – Prof

+0

Мне удалось захватить источник. он не использует ConfigureAwait (false), но если я придерживаюсь .ConfigureAwait после выставленного RenewAuthenatication() он не заторможен (хотя это не очень полезно, поскольку я не могу извлечь результат задачи) – Prof

1

Вам нужно убедиться, что результат RenewAuthentication не перенаправлен обратно в поток пользовательского интерфейса. ConfigureAwait(false) в значительной степени именно с целью, как это:

var renewAwaitable = RenewAuthentication().ConfigureAwait(false); 
var result = renewAwaitable.GetAwaiter().GetResult(); 

Однако, я хотел бы предложить, с выходом все с асинхронным вместо этого. На самом деле нет причин блокировать где-либо в приложении UI - просто отключите все элементы управления, которые нельзя использовать, ожидая возвращения маркера и включите их, когда это произойдет.

+1

закончил тем, что изо всех сил асинхронно. – Prof

Смежные вопросы