WebClient.DownloadDataAsync замораживает мой пользовательский интерфейс

У меня в конструкторе формы после InitializeComponent следующий код:

using (WebClient client = new WebClient())
{
    client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
    client.DownloadDataAsync("http://example.com/version.txt");
}

Когда я запускаю свою форму, пользовательский интерфейс не появляется до тех пор, пока не будет поднят client_DownloadDataCompleted. Метод client_DownloadDataCompleted пуст, поэтому проблем нет.

Что я делаю не так? Как это сделать, не замораживая пользовательский интерфейс?

Спасибо за уделенное время. С уважением.

ПОЛНЫЙ КОД:

Program.cs

using System;
using System.Windows.Forms;

namespace Lala
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form1.cs

using System;
using System.Net;
using System.Windows.Forms;

namespace Lala
{
    public partial class Form1 : Form
    {
        WebClient client = new WebClient();

        public Form1()
        {
            client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
            client.DownloadDataAsync(new Uri("http://www.google.com"));
            InitializeComponent();
        }

        void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            textBox1.Text += "A";
        }
    }

    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name = "disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(12, 12);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(12, 41);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(468, 213);
            this.textBox1.TabIndex = 1;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(492, 266);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBox1;
    }
}

Вы имеете в виду DownloadData или DownloadString?

chakrit 07.11.2008 14:41

Удалось ли вам это решить?

Robert Wagner 13.11.2008 02:16

Разрешение - client.Proxy = null;. См. Ответ на аналогичный вопрос: stackoverflow.com/questions/4415443/…

David Grayson 28.05.2011 04:03

client.Proxy = null не решает всей проблемы ... У меня такая же проблема. Я подозреваю, что во время функции WebClient.DownloadDataAsync () выполняется какое-то синхронное действие.

David Jeske 03.10.2012 23:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
4
7 241
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Вы хотите запустить загрузку в другом потоке, см. это в качестве отправной точки.

Итак ... для чего нужен Async? Если я собираюсь использовать BackgroundWorker, почему я должен использовать DownloadDataAsync вместо DownloadData?

Matías 07.11.2008 14:12

Я пробовал ваш код, и он отлично работает.

Не могли бы вы опубликовать свой метод Main (Args []) и значения a и b при его запуске:

    int a, b;
    ThreadPool.GetMaxThreads(out a, out b);

Я пробовал это в .NET 3.5 и VS2008. Я в недоумении, но убежден, что это связано с настройкой вашего компьютера. Не код. Проверьте эти вещи:

  • Проверьте пул потоков (см. Выше). Получаю a = 250 b = 1000
  • Отключить все сторонние плагины
  • Загрузить VS "Clean" (Вы перезагружались)
  • Закройте как можно больше программ / служб.
  • Проверьте свою конфигурацию IE. Я думаю, что этот класс использует код / ​​настройки IE
  • Брандмауэр? Антивирус?
  • Попробуйте на другом компьютере

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

Jon Skeet 07.11.2008 14:25

Этот код у меня не работает. Я получаю КОНЕЦ ПРИЛОЖЕНИЯ за 1 мс до загруженной строки. Чтобы добраться до "КОНЕЦ ПРИЛОЖЕНИЯ", нужно примерно 5 секунд.

Matías 07.11.2008 14:25

@Matias Я пробовал ваш код, и пользовательский интерфейс полностью отзывчивый. Опубликуйте свой статический основной метод / класс.

Robert Wagner 07.11.2008 14:34

Если я использую ваш код перед Application.Run (new Form1 ()); Я получаю a = 250 и b = 1000.

Matías 07.11.2008 14:47

- a = 250, b = 1000 - плагинов нет, я использую VS2008 Express ... но я пробовал на другом компьютере, где вчера установил VS2008 Pro, и получаю тот же результат. - Никаких изменений. - Я пробовал отключить все в msconfig

Matías 07.11.2008 14:56

Настройки IE кажутся нормальными. Нет прокси, включена только конфигурация автоопределения на всякий случай - Нет брандмауэра (я нахожусь за маршрутизатором, с Wi-Fi, нет потери пакетов, и у меня 169 мс стабильно для Google) - Антивирус NOD отключен

Matías 07.11.2008 14:57

Мне это кажется немного странным.

Попробуйте сохранить ссылку на член WebClient, чтобы не уничтожить его в конструкторе, возможно, он блокируется на клиенте.

Нет, у меня такая же проблема.

Matías 07.11.2008 14:19

НЕ УДАЛЕНО: Поскольку многие думают об использовании блока, как и я, я подтвердил, что он связан с нет.

Можете ли вы удалить блок using, я думаю, он ждет, чтобы удалить экземпляр веб-клиента.

Нет, тот же результат без использования.

Matías 07.11.2008 14:18

Я сильно подозреваю, что это связано с удалением WebClient, пока вы все еще используете его для асинхронного вызова.

Попробуйте удалить оператор using и вместо этого вызовите Dispose в обработчике событий. (Или просто для тестирования, не беспокойтесь о его утилизации.

Если бы вы могли опубликовать короткая, но полная программа, демонстрирующее проблему, это было бы очень удобно.

Спасибо за код. Это странно. У вас есть URL, ответ на который занимает немного больше времени, чем на www.google.com? (Это особенно быстро для меня, поскольку я работаю в Google :)

Jon Skeet 07.11.2008 15:00

хе-хе, вы можете попробовать страницу с медленной загрузкой, например cablemodem.fibertel.com.ar

Matías 07.11.2008 15:02

@Matias: Он использует только первый запрос (а не всю страницу, включая изображения и т. д.), Так что это быстро. Попробую найти большой файл для загрузки ... или использовать мой нетбук через 3G :)

Jon Skeet 07.11.2008 15:08

Оператор using () пытается вызвать Dispose () веб-клиента, пока он все еще загружается. Метод Dispose, вероятно, ожидает завершения загрузки, прежде чем продолжить.

Постарайтесь не использовать оператор using () и избавьтесь от WebClient в событии DownloadDataCompleted.

Помимо удаления чего-то, что, возможно, все еще выполняет асинхронный вызов, о котором говорили другие люди, я НАСТОЯТЕЛЬНО рекомендовал бы не делать такие тяжелые вещи, как это, в конструкторе формы.

Вместо этого сделайте это в переопределении OnLoad, где вы также сможете проверить свойство DesignMode, которое поможет вам избежать нескольких уровней ада с дизайнером форм VS.

Тот же результат при замене OnLoad и использовании Load (не одновременно)

Matías 07.11.2008 15:00

Я могу нормально запустить ваш код. И форма появляется, и загрузка завершается ПОСЛЕ появления формы.

Как вы сказали, у меня нет зависаний.

Я думаю, это как-то связано с окружающей средой, в которой вы его запускаете.

На какой версии .NET / Visual Studio вы работаете?

Visual Studio 2008 Pro (с .net 3.5) и Express ... с одинаковым результатом в обоих

Matías 07.11.2008 14:59

Эммм .... Мне просто любопытно

У вас есть брандмауэры?

Брандмауэры Любые вообще на твоей машине?

Может быть, ZoneAlarm?

Нет. Но я за роутером (использую Wi-Fi). У меня нет потери пакетов на роутер или в гугл. Я получаю стабильную 1 мс для роутера и 169 мс для Google.

Matías 07.11.2008 14:59
Ответ принят как подходящий

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

У меня есть небольшая запись, чтобы указать непосредственно до и после вызовов DownloadDataAsync, а также когда запускается завершенный обработчик. Если я загружаю большой файл через 3G, будет является пауза между «до» и «после», но пользовательский интерфейс появится до того, как файл завершит загрузку.

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

Итак, какой лучший или правильный способ поместить его в другую ветку?

Matías 07.11.2008 16:01

BackgroundWorker, вероятно, был бы самым простым способом, чтобы вы могли легко вернуться к потоку пользовательского интерфейса. Либо так, либо просто запустите новый поток, либо используйте пул потоков.

Jon Skeet 07.11.2008 17:11

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

technophile 08.11.2008 06:13

С другой стороны, сделать его по-настоящему асинхронным было бы очень сложно - и, конечно же, вы все равно должны уметь справляться с исключениями во время загрузок :(

Jon Skeet 08.11.2008 11:24

Я как минимум читал, что разрешение DNS выполняется синхронно до запуска асинхронного HTTP-запроса. См. expert-exchange.com/Web_Development/Software/Q_21982212.htm‌ l

mbeckish 27.11.2008 00:38

Да, это определенно имело бы смысл.

Jon Skeet 27.11.2008 10:06

DownloadDataAsync против DownloadData в потоке без пользовательского интерфейса:

DownloadDataAsync хорош тем, что фактически не связывает поток до обработки DownloadDataCompletedEvent, после того как запрос был сделан и сервер ответил.

Я считаю, что Джон Скит на правильном пути - я читал, что разрешение DNS должно завершиться синхронно, прежде чем асинхронный HTTP-запрос будет поставлен в очередь и вызов DownloadDataAsync вернется.

Может ли разрешение DNS быть медленным?

По моему опыту, он как бы блокирует поток при запуске отладки проекта (запуске его внутри Visual Studio) и при первом доступе к серверу.

При запуске скомпилированного exe блокировка не ощущается.

Я только что протестировал то же самое в проекте WPF под VS2010, .NET 4.

Я загружаю файл с индикатором выполнения, чтобы показать процент выполнения с использованием WebClient.DownloadDataCompleted и т. д.

И, к моему удивлению, я обнаружил то же самое, что упоминал @Dan: Внутри отладчика он забавным образом блокирует поток. При отладке мой индикатор выполнения обновляется на 1%, затем какое-то время ничего не делает, а затем снова внезапно обновляется до 100%. (Операторы Debug.WriteLn печатаются плавно). И между этими двумя моментами пользовательский интерфейс зависает.

Но за пределами отладчика индикатор выполнения плавно перемещается от 0% до 100%, и пользовательский интерфейс никогда не зависает. Чего и следовало ожидать.

Похоже, здесь тоже проблема отладчика.

tofutim 19.10.2012 23:19

попробуй это:

client.Proxy = GlobalProxySelection.GetEmptyProxy();

WebRequest.DefaultWebProxy = null;

Roman Pushkin 05.04.2011 01:05

Обнаружил ту же проблему и нашел решение. Довольно сложное обсуждение здесь: http://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?forum=ncl

Короче говоря, проблема в том, что веб-клиент ищет прокси-серверы и вешает приложение. Помогает следующее решение:

WebClient webClient = new WebClient();
webClient.Proxy = null;
... Do whatever else ...

Установите для свойства Proxy значение null.

linquize 10.01.2015 15:43

Предположительно это нарушает код для всех, кто полагается на конфигурацию прокси Windows.

Quolonel Questions 12.07.2018 01:59

Эта проблема все еще существует даже в VS2015. Я наконец понял это, нет ничего плохого в коде, который используют люди, проблема на самом деле в том, насколько быстро вы можете записывать данные в элемент управления меткой, и это то, что вешает процесс и приводит к зависанию вашего пользовательского интерфейса. Попробуйте заменить ярлыки, на которые вы ссылаетесь, текстовыми полями в обработчиках progresschanged. Это устранило все задержки в пользовательском интерфейсе для меня, я надеюсь, что это поможет другим, поскольку я часами пытался понять, почему код работал иногда, а не другие.

Другие вопросы по теме