Я все еще пытаюсь обернуть голову асинхронным движением, и мне интересно, почему следующий код вызывает тупик. Моим вариантом использования является следующее: у меня есть служебный интерфейс, который пытается абстрагироваться от того, как реализован сервис. Одна из услуг - это веб-сервис, основанный на 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
, потому что он ничего не возвращает, а остальная часть программы не зависит от него.
I подумайте, что вы обнаружите, что на самом деле 'Connect' возвращает очень много * сразу * - потому что это метод асинхронизации. К сожалению, это метод async, возвращающий 'void', что, как правило, является плохим. Вы поставили точки останова или диагностику в 'GetAuthorizationUriAsync', чтобы узнать, как далеко он на самом деле достиг? –
Я не уверен, что вы подразумеваете под «тупиком», если пользовательский интерфейс все еще реагирует. Возвращает ли 'GetAuthorizationUriAsync'? (Кстати, у меня есть несколько [советов в моем блоге] (http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html), чтобы избежать «async void» в конструкторах). –
'GetAuthorizationUriAsync()' получает первый 'ожидание'. Это никогда не доходит до второго. – sohum