Почему асинхронный метод не возвращает ожидаемое немедленно?


Я думал, что это разумный шаблон для асинхронного вызова WebClient DownloadData в обработчике событий:

private async void button1_Click(object sender, EventArgs e)
{
    WebClient wc = new WebClient();
    //wc.Proxy = null;
    byte[] bytes = await wc.DownloadDataTaskAsync("http://www.google.com");
    label1.Text = Encoding.ASCII.GetString(bytes);
}

Но я нахожу блоки DownloadDataTaskAsync примерно за 5 секунд до возвращения (если только не wc.Proxy = оператор null раскомментирован). Какой смысл в том, чтобы метод был ожидаемым, если он может по своей прихоти выполнить нетривиальную работу, даже не возвращая задачу?

- видимому, это означает, чтобы быть безопасным я хотел и не вызов метода xAsync как выше но вместо этого всегда следует заворачивать их в задание.Беги() сам, чтобы убедиться. Или нет?

2   3  

2 ответа:

Это известная проблема с WebClient/HttpWebRequest: прокси-серверы и DNS-запросы всегда выполняются синхронно. Это ошибка, но Microsoft в значительной степени решила не исправлять ее по причинам обратной совместимости.

Первое, что я бы рекомендовал, - это использовать HttpClient. Если это не работает, и вам нужна асинхронность, то вы можете обернуть вызов в Task.Run.

Получается, что WebClient.DownloadDataTaskAsync вызывает HttpWebRequest.BeginGetResponse

MSDN указывает:

Метод BeginGetResponse требует некоторых синхронных задач настройки, чтобы полное (разрешение DNS, обнаружение прокси и подключение к сокету TCP, например) до того, как этот метод станет асинхронным. в результате, этот метод никогда не должен вызываться в потоке пользовательского интерфейса потому что это может занять значительное время (до нескольких минут в зависимости от настроек сети) для завершения начального синхронного задачи установки до того, как возникнет исключение для ошибки или метод преуспевает.

Http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse(v=vs. 110).aspx

К сожалению, документация MSDN для WebClient.DownloadDataTaskAsync говорит:

Эта операция не блокируется.

Что, похоже, не совсем верно.