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 - Программа.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());
}
}
}
Форма 1.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;
}
}
Решение
Теперь, когда у нас есть полный код, я могу сказать, что я определенно не вижу проблемы - во всяком случае, не совсем так, как описано.
У меня есть немного записей в журнале, чтобы указать непосредственно перед и после вызовов DownloadDataAsync и при запуске завершенного обработчика.Если я загружу большой файл через 3G, там является пауза между "до" и "после", но пользовательский интерфейс появляется задолго до завершения загрузки файла.
У меня есть подозрение, что Контакты выполняется синхронно, но фактическая загрузка является асинхронной.Конечно, это все еще прискорбно - и, возможно, лучше перенести все это в другую тему, - но если я прав, об этом, по крайней мере, стоит знать.
Другие советы
Столкнулся с той же проблемой и нашел решение.Здесь довольно сложная дискуссия:http://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?форум=ncl
Короче говоря, проблема в том, что веб-клиент ищет прокси-серверы и зависает приложение.Помогает следующее решение:
WebClient webClient = new WebClient();
webClient.Proxy = null;
... Do whatever else ...
Вы хотите запустить загрузку в другом потоке, см. это в качестве отправной точки.
Я сильно подозреваю, что это связано с удалением WebClient, пока вы все еще используете его для асинхронного вызова.
Попробуйте удалить инструкцию using и вместо этого вызвать Dispose в обработчике событий.(Или просто для тестирования, вообще не беспокойтесь о его утилизации.
Если бы вы могли опубликовать короткая, но полная программа который демонстрирует проблему, это было бы действительно удобно.
Помимо удаления чего-либо, что, возможно, все еще выполняет асинхронный вызов, о котором упоминали другие люди, я бы НАСТОЯТЕЛЬНО рекомендовал не делать подобные тяжеловесные вещи в конструкторе формы.
Вместо этого сделайте это в переопределении OnLoad, где вы также сможете проверить свойство DesignMode, которое поможет вам избежать нескольких уровней ада с конструктором VS forms.
ВОССТАНОВЛЕННЫЙ: Поскольку многие думают о блоке using так же, как и я, я подтвердил, что это так не Похожие.
Можете ли вы удалить блок using, я думаю, он ожидает удаления экземпляра webclient.
DownloadDataAsync противЗагружаемые данные в потоке, отличном от пользовательского интерфейса:
DownloadDataAsync хорош тем, что он фактически не связывает поток до обработки DownloadDataCompletedEvent, после того как запрос был сделан и сервер ответил.
Я считаю, что Джон Скит на правильном пути - я читал, что разрешение DNS должно выполняться синхронно, прежде чем асинхронный HTTP-запрос будет помещен в очередь и вернется вызов DownloadDataAsync.
Может ли разрешение DNS быть медленным?
Я только что протестировал то же самое в проекте WPF под VS2010, .NET 4.
Я загружаю файл с индикатором выполнения, чтобы показать процент выполнения с помощью WebClient.DownloadDataCompleted и т.д.
И, к моему изумлению, я нахожу то же самое, о чем упоминал @Dan:Внутри отладчика это блокирует поток забавным образом.При отладке мой индикатор выполнения обновляется на 1%, затем некоторое время ничего не делает, затем внезапно обновляется снова на 100%.(Отладка.Инструкции WriteLn печатаются плавно повсюду).И между этими двумя моментами пользовательский интерфейс замораживается.
Но вне отладчика индикатор выполнения плавно перемещается с 0% на 100%, и пользовательский интерфейс никогда не зависает.Именно этого и следовало ожидать.
попробуй это:
client.Proxy = GlobalProxySelection.GetEmptyProxy();
По-моему, это выглядит немного странно.
Попробуйте сохранить ссылку на элемент WebClient, чтобы не уничтожать его в конструкторе, возможно, он блокируется на клиенте.Dispose()
Оператор using() пытается вызвать функцию Dispose() веб-клиента, пока он все еще загружается.Метод Dispose, вероятно, ожидает завершения загрузки, прежде чем продолжить.
Попробуйте не использовать инструкцию using() и утилизируйте WebClient в вашем событии DownloadDataCompleted.
Я могу нормально запустить ваш код.И форма появляется, и загрузка завершается ПОСЛЕ того, как форма появилась.
У меня нет никаких зависаний, как вы упомянули.
Я думаю, это как-то связано со средой, в которой вы его запускаете.
На какой версии .NET / Visual Studio вы работаете?
Я попробовал ваш код, и он работает нормально.
Не могли бы вы опубликовать свой основной метод (Args[]) и значения a и b при его запуске:
int a, b;
ThreadPool.GetMaxThreads(out a, out b);
Я пробовал это в .NET 3.5 и VS2008.Я в растерянности, но я убежден, что это связано с настройками на вашем компьютере.Не из-за кода.Проверьте эти вещи:
- Проверьте пул потоков (выше).Я получаю a = 250 b = 1000
- Отключите все сторонние плагины
- Загрузка ПРОТИВ "Очистки" (вы перезагрузились)
- Закройте как можно больше программ / сервисов
- Проверьте конфигурацию вашего IE.Я думаю, что этот класс использует IE code / settings
- Брандмауэр?АнтиВирус?
- Попробуйте это на другом компьютере
Ммм....Мне просто любопытно
У вас включены какие-нибудь брандмауэры?
Любой брандмауэры вообще есть на вашем компьютере?
Может быть, ZoneAlarm?
По моему опыту, это как бы блокирует поток при запуске отладки проекта (запуск его внутри Visual Studio) и при первом обращении к серверу.
При запуске скомпилированного exe-файла блокировка не воспринимается.
Эта проблема все еще сохраняется даже в VS2015.Я, наконец, понял это, в коде, который используют люди, нет ничего плохого, проблема на самом деле в том, как быстро вы можете записывать данные в элемент управления label, и именно это останавливает процесс и приводит к зависанию вашего пользовательского интерфейса.Попробуйте заменить свои метки, на которые вы ссылаетесь, текстовыми полями в ваших обработчиках progresschanged.Это решило все задержки в пользовательском интерфейсе для меня, я надеюсь, что это поможет другим, поскольку я потратил часы, пытаясь понять, почему код работал иногда, а не другие.