2013-09-26 4 views
-2

Я все еще пытаюсь обернуть голову асинхронным движением, и мне интересно, почему следующий код вызывает тупик. Моим вариантом использования является следующее: у меня есть служебный интерфейс, который пытается абстрагироваться от того, как реализован сервис. Одна из услуг - это веб-сервис, основанный на OAuth. Интерфейс службы имеет метод Connect(), который должен использовать любой пользователь, использующий интерфейс, перед его использованием.HttpClient ждут зависания на PostAsync с методом async void

На моей стороне клиента я создаю свой конкретный объект службы и вызываю Connect() в моем конструкторе представления (это прототип, поэтому я просто пытаюсь получить доказательство концепции). В службе на основе OAuth вызов соединения требует получения токена доступа, поэтому он (пытается) делает это асинхронно. Этот вызов Connect() никогда не возвращается, и приложение зашло в тупик (но пользовательский интерфейс активен). Я предполагаю, что я запутался и пытался синхронно использовать мой клиент где-то, но я не уверен, где.

управления

public class MainWindow 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     _webService = new OAuthBasedWebService(); 
     _webService.ShowAuthorizationPage += _webService_ShowAuthorizationPage; // this is defined on the concrete object -- i know, bad design 
     _webService.Connect(); 
    } 
} 

OAuth на основе вебсервис

public class OAuthBasedWebService() 
{ 
    private OAuthWrapper _wrapper; 

    public async void Connect() 
    { 
     var uri = await _wrapper.GetAuthorizationUri(); 
     OnShowAuthorizationPage(uri); 
    } 
} 

internal class OAuthWrapper 
{ 
    public async Task<Uri> GetAuthorizationUri() 
    { 
     var uri = await _consumer.GetAuthorizationUriAsync(); 
     return uri; 
    } 
} 

internal class OAuthConsumer 
{ 
    public async Task<Uri> GetAuthorizationUriAsync() 
    { 
     using (var client = new HttpClient()) 
     { 
      client.BaseAddress = "webservicebaseaddress"; 
      var content = new FormUrlEncodedContent(new [] 
      { 
       CreateParameter("oauth_consumer_key", "consumerkey"), 
       CreateParameter("oauth_consumer_secret", "consumersecret") 
       // etc., etc. 
      }); 

      var response = await client.PostAsync("/method_path", content).ConfigureAwait(false); 
      var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); 

      // parse authorization uri from responseContent 
      return authorizationUri; 
     } 
    } 
} 

Я знаю, что дизайн должен немного поработать, но я пытаюсь понять, почему это запиранием. Я предполагаю, что это потому, что _webService.Connect() не вызывается асинхронно, но я также не могу await, потому что он ничего не возвращает, а остальная часть программы не зависит от него.

+1

I подумайте, что вы обнаружите, что на самом деле 'Connect' возвращает очень много * сразу * - потому что это метод асинхронизации. К сожалению, это метод async, возвращающий 'void', что, как правило, является плохим. Вы поставили точки останова или диагностику в 'GetAuthorizationUriAsync', чтобы узнать, как далеко он на самом деле достиг? –

+1

Я не уверен, что вы подразумеваете под «тупиком», если пользовательский интерфейс все еще реагирует. Возвращает ли 'GetAuthorizationUriAsync'? (Кстати, у меня есть несколько [советов в моем блоге] (http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html), чтобы избежать «async void» в конструкторах). –

+0

'GetAuthorizationUriAsync()' получает первый 'ожидание'. Это никогда не доходит до второго. – sohum

ответ

1

Я не уверен, почему вы используете событие здесь, если проблема была только потому, что вы не могли бы сделать конструктор «асинхр», а затем просто переместить вызов CONECT другому методу:

public class MainWindow 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     Init(); 
    } 

    public async void Init(){ 

     _webService = new OAuthBasedWebService(); 

     Uri uri=await _webService.Connect(); 
     _webService_ShowAuthorizationPage(uri); 
    } 
} 


public class OAuthBasedWebService() 
{ 
    private OAuthWrapper _wrapper; 

    public async Task<Uri> Connect() 
    { 
     return await _wrapper.GetAuthorizationUri(); 

    } 
} 
+0

Событие существует, потому что Connect не всегда запрашивает страницу авторизации. Если пользователь уже авторизовался, например, страница авторизации не будет отображаться. – sohum

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