2015-09-03 2 views
0

В результате моего вопроса about TaskCompletionSourceгрецкого oauthService.GetTokensAsync не показывает диалоговое

Я попробовал подобную технику для получения токенов

private t.Task<OAuthTokens> GetOAuthTokens() 
    { 
     var tcs = new t.TaskCompletionSource<OAuthTokens>(); 
     t.Task.Run(
      async() => 
      { 
       var oauthService = new OAuthService(_configurationCloud); 
       var code = OAuthLogin.GetAuthorizationCode(_configurationCloud); 
       var response = await oauthService.GetTokensAsync(code); 

       tcs.SetResult(response); 
      }); 
     return tcs.Task; 
    } 

называют это с помощью

var task1 = GetOAuthTokens(); 
_oAuthKeyService.OAuthResponse = task1.Result; 

Однако программа блокируется, когда я запускаю его.

следующие работы OK

 var oauthService = new OAuthService(_configurationCloud); 
     var code = OAuthLogin.GetAuthorizationCode(_configurationCloud); // causes a login dialog 
     var tokens = oauthService.GetTokens(code); 
     _oAuthKeyService.OAuthResponse = tokens; 

и выводит диалоговое окно авторизации.

+0

@shaun_a_wilde пожалуйста, вы можете помочь? –

+0

Какой интерфейс? если это насос сообщений, основанный как WinForms или WPF, он должен блокироваться. Почему вы используете 'Task.Run' и' TaskCompletionSource' для вызова уже асинхронного кода? –

+0

Я отредактировал вопрос, чтобы уточнить, что это программа, которая блокируется, а не пользовательский интерфейс. (Мне нужно Ctrl Alt Delete, чтобы закончить программу). Я использую Task.Run и TaskCompletionSource, чтобы дождаться выполнения задачи. Существует синхронный вариант .GetTokens, но я экспериментирую. –

ответ

4

Когда я ответил на ваш previous question, я предположил, что у вас есть требование использовать объект TaskCompletionSource, поэтому я сожалею, если он отправил вас в неправильном направлении. Поскольку Paulo сказал, что обычно вам не нужно использовать TaskCompletionSource с кодом async/await, но вам нужно немного понять, как его использовать.

Вызов Result Задача приведет к блокировке потока, теперь в потоке, отличном от UI, это не такая проблема (просто не идеальная), но в потоке пользовательского интерфейса это фактически остановит ваш UI from responding, пока задача не будет завершен, если предположить, что он просто не прекращается полностью из-за тупика.

Главное, чтобы узнать, как использовать async/await в среде пользовательского интерфейса, потому что для его работы вы также используете async/wait везде, иначе вы в конечном итоге попытаетесь использовать Task.Result для доступа к вашим данным и получения заблокированный поток пользовательского интерфейса для ваших проблем.

Это хороший гид стартер - https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Теперь предположим, что вы тянете code со страницы, как это (мощеной из code samples на GitHub), а затем извлечения лексем.

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
{ 
    var content = webBrowser1.DocumentText; 
    var regex = new Regex(@"\<title\>(.+?)=(.+?)\</title\>"); 
    var match = regex.Match(content); 
    if (!match.Success || match.Groups.Count != 3) 
     return; 

    switch (match.Groups[1].Value.ToLowerInvariant()) 
    { 
     case "code": // we have a code 
      var code = match.Groups[2].Value; 
      var config = new ApiConfiguration(Configuration.ClientId, Configuration.ClientSecret, Configuration.RedirectUrl); 
      var service = new OAuthService(config, new WebRequestFactory(config)); 
      var tokens = service.GetTokensAsync(code).Result; // <= blocking 
      _keyService.OAuthResponse = tokens; 
      break; 

     case "error": // user probably said "no thanks" 
      webBrowser1.Navigate(_logoffUri); 
      break; 
    } 
} 

однако ваш код блокировка на .Result

Что вам нужно сделать, это использовать асинхронные/ОЖИДАНИЕ всего путь, однако при использовании ждать жалуется на отсутствии асинхронного о методе, так , просто добавьте его; да, это разрешено, и есть много статей и сообщений в блогах об этом, что catch people new to async/await в интерфейсе winforms/wpf.

например.

// we add async to the callback - yup it's allowed 
private async void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
{ 
    var content = webBrowser1.DocumentText; 
    var regex = new Regex(@"\<title\>(.+?)=(.+?)\</title\>"); 
    var match = regex.Match(content); 
    if (!match.Success || match.Groups.Count != 3) 
     return; 

    switch (match.Groups[1].Value.ToLowerInvariant()) 
    { 
     case "code": // we have a code 
      var code = match.Groups[2].Value; 
      var config = new ApiConfiguration(Configuration.ClientId, Configuration.ClientSecret, Configuration.RedirectUrl); 
      var service = new OAuthService(config, new WebRequestFactory(config)); 
      var tokens = await service.GetTokensAsync(code); // <= now we can use await here => non-blocking 
      _keyService.OAuthResponse = tokens; 
      break; 

     case "error": // user probably said "no thanks" 
      webBrowser1.Navigate(_logoffUri); 
      break; 
    } 
} 

Я uploaded the code as gist Я надеюсь, что это помогает

+0

Спасибо Шон. Я получаю, что следующие блоки: var tokens = service.GetTokensAsync (code) .Result; Я получаю, что я могу использовать service.GetTokens() вместо этого, который также будет блокироваться. Я не понимаю, почему диалоговое окно входа в систему появляется только при использовании service.GetTokens(). Когда я использую опцию Async, программа блокируется и никогда не разблокируется. Как будто диалог входа в систему невидим. –

+2

@ kirsteng - с небольшими отсканированными текстами трудно сказать - реализация GetTokens [доступна] (https://github.com/MYOB-Technology/AccountRight_Live_API_.Net_SDK/blob/master/MYOB.API.SDK/SDK/ Services/OAuthService.cs # L64) на github фактически использует альтернативный асинхронный подход, который не зависит от шаблона async/await - поэтому его можно использовать с версиями фреймворка, которые не имеют async/await, например .NET2. –

+0

Спасибо Shaun, я просто собираюсь использовать не асинхронную версию GetTokens() на данный момент. –