【问题标题】:How can I get more information from WebClient.DownloadDataAsync() while it's connecting?连接时如何从 WebClient.DownloadDataAsync() 获取更多信息?
【发布时间】:2016-02-29 16:25:24
【问题描述】:

我用它来下载文件...

WebClient wc = new WebClient();
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadDataCompleted +=new DownloadDataCompletedEventHandler(wc_DownloadDataCompleted);
wc.DownloadDataAsync(new Uri("http://www.example.com/myfile.exe"));

我有这样的事件处理程序...

private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    //There has been some type of progress with the download
}

private void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
    //The download has finished
}

一切都很好!我遇到的问题是调用 DownloadDataAsync() 时的延迟。一旦我调用它,在 WebClient 下载第一块数据之前,我似乎根本没有任何类型的进度报告。在那个时候,用户界面看起来像是在等待用户输入等……

有什么方法可以获取有关此时间范围内正在发生的事情的更多信息?我确定它正在解析主机、发送用户/通行证信息等。我希望获得一些进展,以便我可以更新我的 UI。

【问题讨论】:

    标签: c# winforms .net-4.0 webclient


    【解决方案1】:

    如果您不想重新实现默认 WebClient 以在 DNS 查找完成时发送事件、协商安全通道、打开连接的套接字、交换 http-headers 以命名一些,您可以在使用 winclient 的场景中滥用内置日志记录。

    想法如下:您配置一个自定义 TraceListener,它将由 System.Net TraceSource 记录的消息提供。如果将跟踪源配置为详细日志记录,则会收到消息,指示任何正在进行的连接的进度。侦听器为收到的每条消息引发事件,您可以在应用程序中订阅这些事件。

    这里是TraceListener的实现:

    /// <summary>
    /// holds the message being send to the listener
    /// </summary>
    public class DetailedProgressEventArgs:EventArgs
    {
        public string Message;
        public DetailedProgressEventArgs(string msg)
        {
            Message = msg;
        }
    }
    
    /// <summary>
    /// enables sending events when a log message is written
    /// </summary>
    /// <param name="sender">the instance that sends the event</param>
    /// <param name="e">the actual message</param>
    public delegate void DetailedProgressEventHandler(object sender, DetailedProgressEventArgs e);
    
    /// <summary>
    /// Used as a TraceListener and wired in the app.config to receive System.Net messages
    /// </summary>
    public class DetailedProgressListener : TraceListener
    {
        // wire the event handlers here
        static public event DetailedProgressEventHandler ProgressChanged;
    
        public override void Write(string message)
        {
            // let's do nothing
        }
    
        /// <summary>
        /// rasies a progessChanged event for every message
        /// </summary>
        /// <param name="message"></param>
        public override void WriteLine(string message)
        {
            var pch = ProgressChanged;
            if (pch!=null)
            {
                pch.Invoke(this, new DetailedProgressEventArgs(message));
            }
        }
    }
    

    这就是你需要添加到你的 app.config 以获得diagnostic logging enabled

    <configuration>
        <system.diagnostics>
          <sources>
            <source name="System.Net" tracemode="includehex" maxdatasize="1024">
              <listeners>
                <add name="ProgressListener"/>
              </listeners>
            </source>
          </sources>
          <switches>
            <add name="System.Net" value="Verbose"/>
          </switches>
          <sharedListeners>
            <add name="ProgressListener"
              type="YourApp.DetailedProgressListener, YourApp" />
          </sharedListeners>
          <trace autoflush="true"/>
        </system.diagnostics>
    </configuration>
    

    我为控制台应用程序创建了一个小型实现示例。我假设这提供了足够的细节来适应你自己的实现场景,无论是使用多行文本框还是进度条:

    Console.BackgroundColor = ConsoleColor.Black;
    
    // handle hidden progress
    DetailedProgressEventHandler progress = (s, e) =>
        {
            var old = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.Write("+");
            Debug.WriteLine(e.Message);
            Console.ForegroundColor = old;
        };
    
    // hookup the event
    DetailedProgressListener.ProgressChanged += progress;
    
    using(var wc = new WebClient())
    {
        wc.DownloadProgressChanged += (s, e) => {
            // stop once we have normal progress
            DetailedProgressListener.ProgressChanged -= progress;
    
            var old = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.DarkRed;
            Console.Write(e.BytesReceived);
            Console.Write(" ,");
            Console.ForegroundColor = old;
        };
        wc.DownloadDataCompleted += (s, e) =>
        {
            var old = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(" Done");
            Console.ForegroundColor = old;
        };
    
        wc.DownloadDataAsync(new Uri("https://stackoverflow.com"));
    }
    Console.ReadLine();
    

    我的输出如下所示:

    黄色的+ 是在调用 TraceListener 时写入的。其余的是从 WebClient 引发的 normal 事件中接收到的数据。

    请记住,侦听器对于应用程序是全局的。因此,如果您也有使用 System.Net 类的后台线程,您还将获得这些事件。解析消息以实现某种关联,或者如果这变得脆弱,则使用额外的 ProgressEvents 实现您自己的 WebClient。

    【讨论】:

    • 这很棒,而且这个概念看起来很扎实!我得试一试。老实说,我最终作弊,只是用计时器伪造 DNS 查找和用户/通过身份验证...... :)
    猜你喜欢
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    • 2011-01-05
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    相关资源
    最近更新 更多