如何在连接时从 WebClient.DownloadDataAsync() 获取更多信息?

How can I get more information from WebClient.DownloadDataAsync() while it's connecting?

我用这个来下载文件...

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 看起来像是在等待用户输入等...

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

如果您不想 re-implement 默认 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>

我为控制台应用程序创建了一个小的实施示例。我假设这提供了足够的细节以使其适应您自己的实施方案,使用 multi-line 文本框或进度条:

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://whosebug.com"));
}
Console.ReadLine();

我的输出如下所示:

黄色+是调用TraceListener时写的。其余的是从 WebClient 引发的 正常 事件接收的数据。

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