You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebClient的DownloadFileCompleted事件触发过早问题排查求助

问题原因及修复方案

1. 事件订阅顺序错误

你在调用webClient.DownloadFileAsync()之后才订阅DownloadProgressChanged和DownloadFileCompleted事件,这会导致程序可能错过初始进度事件,甚至如果下载在订阅完成前就意外终止(比如触发错误),事件处理逻辑根本不会执行。

修复:先订阅事件,再启动异步下载:

webClient = new WebClient();
// 先绑定事件
webClient.DownloadProgressChanged += DownloadProgressChanged;
webClient.DownloadFileCompleted += DownloadFileCompleted;
// 再开始下载
webClient.DownloadFileAsync(uri, currentFile);

2. 未处理下载异常

DownloadFileCompleted事件触发不代表下载成功,也可能是发生了网络错误、文件权限不足、URI无效等问题。你必须在事件处理方法中检查错误状态:

private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    if (e.Error != null)
    {
        if (cbDebug.Checked)
            rtbDebug.Text += Environment.NewLine + $"下载失败: {e.Error.Message}";
        fileComplete = true;
        return;
    }
    if (e.Cancelled)
    {
        if (cbDebug.Checked)
            rtbDebug.Text += Environment.NewLine + "下载已取消";
        fileComplete = true;
        return;
    }
    // 下载成功逻辑
    if (cbDebug.Checked)
        rtbDebug.Text += Environment.NewLine + $"下载完成: {currentFile}";
    fileComplete = true;
}

3. 阻塞UI线程的风险(若此方法在UI线程执行)

用while (!fileComplete) { Thread.Sleep(1200); }等待下载完成,会导致UI线程冻结,WebClient的异步回调因为依赖UI线程执行,会被Sleep阻塞,出现进度不更新、事件触发延迟的问题。

修复:改用async/await替代循环等待,让线程在等待期间能处理UI消息:

private async void DownloadFiles()
{
    foreach (Patch patch in patches)
    {
        fileDownloadElapsed.Reset();
        fileDownloadElapsed.Start();

        CurrentPatch = patch;

        Uri uri = new Uri(patch.Uri);
        string uriPath = uri.OriginalString;
        currentFile = uriPath.Substring(uriPath.LastIndexOf('/') + 1);

        if (cbDebug.Checked)
            rtbDebug.Text += Environment.NewLine + string.Format("Downloading {0}...", currentFile.ToLower());

        using (var webClient = new WebClient())
        {
            webClient.DownloadProgressChanged += DownloadProgressChanged;
            
            try
            {
                await webClient.DownloadFileTaskAsync(uri, currentFile);
                if (cbDebug.Checked)
                    rtbDebug.Text += Environment.NewLine + $"下载完成: {currentFile}";
            }
            catch (Exception ex)
            {
                if (cbDebug.Checked)
                    rtbDebug.Text += Environment.NewLine + $"下载失败: {ex.Message}";
            }
        }
    }

    currentFile = string.Empty;
    updateComplete = true;
    progbarValue = 0;
    labelText = "Ready";
}

4. 线程安全问题

fileComplete被多线程访问(主线程循环检查、回调线程赋值),可能出现线程竞争导致逻辑错误。如果坚持用原循环等待方式,需加锁保护变量:

private readonly object _lockObj = new object();
private bool fileComplete;

// 回调中赋值
lock (_lockObj)
{
    fileComplete = true;
}

// 循环中检查
while (true)
{
    lock (_lockObj)
    {
        if (fileComplete) break;
    }
    Thread.Sleep(100); // 缩短休眠时间,提升检查及时性
}

内容的提问来源于stack exchange,提问作者Robert Weaver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 13:17:32