У меня в конструкторе формы после 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;
}
}
Удалось ли вам это решить?
Разрешение - client.Proxy = null;. См. Ответ на аналогичный вопрос: stackoverflow.com/questions/4415443/…
client.Proxy = null не решает всей проблемы ... У меня такая же проблема. Я подозреваю, что во время функции WebClient.DownloadDataAsync () выполняется какое-то синхронное действие.





Вы хотите запустить загрузку в другом потоке, см. это в качестве отправной точки.
Итак ... для чего нужен Async? Если я собираюсь использовать BackgroundWorker, почему я должен использовать DownloadDataAsync вместо DownloadData?
Я пробовал ваш код, и он отлично работает.
Не могли бы вы опубликовать свой метод Main (Args []) и значения a и b при его запуске:
int a, b;
ThreadPool.GetMaxThreads(out a, out b);
Я пробовал это в .NET 3.5 и VS2008. Я в недоумении, но убежден, что это связано с настройкой вашего компьютера. Не код. Проверьте эти вещи:
@Matias: Ответчики не должны предоставлять полную программу, демонстрирующую проблему - пожалуйста, помогите нам помочь вам, упростив нам воспроизведение.
Этот код у меня не работает. Я получаю КОНЕЦ ПРИЛОЖЕНИЯ за 1 мс до загруженной строки. Чтобы добраться до "КОНЕЦ ПРИЛОЖЕНИЯ", нужно примерно 5 секунд.
@Matias Я пробовал ваш код, и пользовательский интерфейс полностью отзывчивый. Опубликуйте свой статический основной метод / класс.
Если я использую ваш код перед Application.Run (new Form1 ()); Я получаю a = 250 и b = 1000.
- a = 250, b = 1000 - плагинов нет, я использую VS2008 Express ... но я пробовал на другом компьютере, где вчера установил VS2008 Pro, и получаю тот же результат. - Никаких изменений. - Я пробовал отключить все в msconfig
Настройки IE кажутся нормальными. Нет прокси, включена только конфигурация автоопределения на всякий случай - Нет брандмауэра (я нахожусь за маршрутизатором, с Wi-Fi, нет потери пакетов, и у меня 169 мс стабильно для Google) - Антивирус NOD отключен
Мне это кажется немного странным.
Попробуйте сохранить ссылку на член WebClient, чтобы не уничтожить его в конструкторе, возможно, он блокируется на клиенте.
Нет, у меня такая же проблема.
НЕ УДАЛЕНО: Поскольку многие думают об использовании блока, как и я, я подтвердил, что он связан с нет.
Можете ли вы удалить блок using, я думаю, он ждет, чтобы удалить экземпляр веб-клиента.
Нет, тот же результат без использования.
Я сильно подозреваю, что это связано с удалением WebClient, пока вы все еще используете его для асинхронного вызова.
Попробуйте удалить оператор using и вместо этого вызовите Dispose в обработчике событий. (Или просто для тестирования, не беспокойтесь о его утилизации.
Если бы вы могли опубликовать короткая, но полная программа, демонстрирующее проблему, это было бы очень удобно.
Спасибо за код. Это странно. У вас есть URL, ответ на который занимает немного больше времени, чем на www.google.com? (Это особенно быстро для меня, поскольку я работаю в Google :)
хе-хе, вы можете попробовать страницу с медленной загрузкой, например cablemodem.fibertel.com.ar
@Matias: Он использует только первый запрос (а не всю страницу, включая изображения и т. д.), Так что это быстро. Попробую найти большой файл для загрузки ... или использовать мой нетбук через 3G :)
Оператор using () пытается вызвать Dispose () веб-клиента, пока он все еще загружается. Метод Dispose, вероятно, ожидает завершения загрузки, прежде чем продолжить.
Постарайтесь не использовать оператор using () и избавьтесь от WebClient в событии DownloadDataCompleted.
Помимо удаления чего-то, что, возможно, все еще выполняет асинхронный вызов, о котором говорили другие люди, я НАСТОЯТЕЛЬНО рекомендовал бы не делать такие тяжелые вещи, как это, в конструкторе формы.
Вместо этого сделайте это в переопределении OnLoad, где вы также сможете проверить свойство DesignMode, которое поможет вам избежать нескольких уровней ада с дизайнером форм VS.
Тот же результат при замене OnLoad и использовании Load (не одновременно)
Я могу нормально запустить ваш код. И форма появляется, и загрузка завершается ПОСЛЕ появления формы.
Как вы сказали, у меня нет зависаний.
Я думаю, это как-то связано с окружающей средой, в которой вы его запускаете.
На какой версии .NET / Visual Studio вы работаете?
Visual Studio 2008 Pro (с .net 3.5) и Express ... с одинаковым результатом в обоих
Эммм .... Мне просто любопытно
У вас есть брандмауэры?
Брандмауэры Любые вообще на твоей машине?
Может быть, ZoneAlarm?
Нет. Но я за роутером (использую Wi-Fi). У меня нет потери пакетов на роутер или в гугл. Я получаю стабильную 1 мс для роутера и 169 мс для Google.
Теперь, когда у нас есть полный код, я могу сказать, что определенно не вижу проблемы - во всяком случае, не совсем так, как описано.
У меня есть небольшая запись, чтобы указать непосредственно до и после вызовов DownloadDataAsync, а также когда запускается завершенный обработчик. Если я загружаю большой файл через 3G, будет является пауза между «до» и «после», но пользовательский интерфейс появится до того, как файл завершит загрузку.
У меня есть подозрение, что соединять выполняется синхронно, но фактическая загрузка асинхронная. Это, конечно, все еще прискорбно - и, возможно, перетащить все это в другой поток - это выход, но если я прав, об этом, по крайней мере, стоит знать.
Итак, какой лучший или правильный способ поместить его в другую ветку?
BackgroundWorker, вероятно, был бы самым простым способом, чтобы вы могли легко вернуться к потоку пользовательского интерфейса. Либо так, либо просто запустите новый поток, либо используйте пул потоков.
Если вы правы и соединение выполняется синхронно, это имеет смысл - это очень упрощает обработку наиболее распространенного исключения (отказ соединения). Обработка исключений в асинхронных обратных вызовах намного сложнее, но исключения во время загрузки, вероятно, встречаются реже.
С другой стороны, сделать его по-настоящему асинхронным было бы очень сложно - и, конечно же, вы все равно должны уметь справляться с исключениями во время загрузок :(
Я как минимум читал, что разрешение DNS выполняется синхронно до запуска асинхронного HTTP-запроса. См. expert-exchange.com/Web_Development/Software/Q_21982212.htm l
Да, это определенно имело бы смысл.
DownloadDataAsync против DownloadData в потоке без пользовательского интерфейса:
DownloadDataAsync хорош тем, что фактически не связывает поток до обработки DownloadDataCompletedEvent, после того как запрос был сделан и сервер ответил.
Я считаю, что Джон Скит на правильном пути - я читал, что разрешение DNS должно завершиться синхронно, прежде чем асинхронный HTTP-запрос будет поставлен в очередь и вызов DownloadDataAsync вернется.
Может ли разрешение DNS быть медленным?
По моему опыту, он как бы блокирует поток при запуске отладки проекта (запуске его внутри Visual Studio) и при первом доступе к серверу.
При запуске скомпилированного exe блокировка не ощущается.
Я только что протестировал то же самое в проекте WPF под VS2010, .NET 4.
Я загружаю файл с индикатором выполнения, чтобы показать процент выполнения с использованием WebClient.DownloadDataCompleted и т. д.
И, к моему удивлению, я обнаружил то же самое, что упоминал @Dan: Внутри отладчика он забавным образом блокирует поток. При отладке мой индикатор выполнения обновляется на 1%, затем какое-то время ничего не делает, а затем снова внезапно обновляется до 100%. (Операторы Debug.WriteLn печатаются плавно). И между этими двумя моментами пользовательский интерфейс зависает.
Но за пределами отладчика индикатор выполнения плавно перемещается от 0% до 100%, и пользовательский интерфейс никогда не зависает. Чего и следовало ожидать.
Похоже, здесь тоже проблема отладчика.
попробуй это:
client.Proxy = GlobalProxySelection.GetEmptyProxy();
WebRequest.DefaultWebProxy = null;
Обнаружил ту же проблему и нашел решение. Довольно сложное обсуждение здесь: 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.
Предположительно это нарушает код для всех, кто полагается на конфигурацию прокси Windows.
Эта проблема все еще существует даже в VS2015. Я наконец понял это, нет ничего плохого в коде, который используют люди, проблема на самом деле в том, насколько быстро вы можете записывать данные в элемент управления меткой, и это то, что вешает процесс и приводит к зависанию вашего пользовательского интерфейса. Попробуйте заменить ярлыки, на которые вы ссылаетесь, текстовыми полями в обработчиках progresschanged. Это устранило все задержки в пользовательском интерфейсе для меня, я надеюсь, что это поможет другим, поскольку я часами пытался понять, почему код работал иногда, а не другие.
Вы имеете в виду DownloadData или DownloadString?