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

C# WebClient的DownloadFileAsync执行正常但无法下载文件问题求助

问题原因
  • WebClient局部变量被GC提前回收:你代码中WebClient是Update方法内的局部变量,调用DownloadFileAsync后方法会立即返回,此时局部变量wc没有任何根引用,GC运行时会直接回收该对象,导致还在执行的异步下载任务被强制终止,文件自然无法完整写入甚至不会被创建。
  • 异步异常未被捕获:DownloadFileCompleted事件回调中的异常不会被Update方法内的try/catch捕获,就算下载过程中出现报错,上层逻辑也感知不到,所以你会得到「代码运行无报错」的假象。
  • 若你的程序是控制台程序、或者调用Update方法后进程很快退出,异步下载还没执行完进程就结束,也会导致没有生成目标文件。
解决方法
  1. 将WebClient改为类级成员变量,避免被GC提前回收,示例修改代码如下:
// 把WebClient声明在类层级,不要放在Update方法内部
private WebClient _wc;

/// <summary>  
/// 下载更新  
/// </summary>  
public string Update()
{
    string result = "";
    try
    {
        if (!isUpdate)
            return result;
        // 初始化类级别的WebClient
        _wc = new WebClient();
        string filename = "Update_NewVersion.zip";
        // 建议用Path.Combine拼接路径,避免手动写斜杠出错
        filename = Path.Combine(Path.GetDirectoryName(loadFile), filename);

        FinalZipName = filename;

        _wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
        _wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
        _wc.DownloadFileAsync(new Uri(download), filename);
        return result = $"download:{download},filename:{filename}";
    }
    catch (Exception ex)
    {
        throw new Exception("更新出现错误,网络连接失败!" + ex.Message);
    }
}

void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
    (sender as WebClient).Dispose();
    // 不要直接抛异常,改成记录错误或者通过回调/事件通知上层
    if (e.Error != null)
    {
        // 此处可写入日志、或者定义错误事件对外通知
        Console.WriteLine($"下载出错:{e.Error.Message}");
        _wc = null;
        return;
    }
    _wc = null;
    isFinish();
}
  1. 如果需要等待下载完成再执行后续逻辑,可将基于事件的异步模式转为Task等待,避免提前释放资源:
public async Task<string> UpdateAsync()
{
    string result = "";
    try
    {
        if (!isUpdate)
            return result;
        using var wc = new WebClient();
        string filename = "Update_NewVersion.zip";
        filename = Path.Combine(Path.GetDirectoryName(loadFile), filename);
        FinalZipName = filename;

        wc.DownloadProgressChanged += (s, e) =>
        {
            CommonMethod.autostep = e.ProgressPercentage;
        };
        // 用TaskCompletionSource包装异步事件
        var tcs = new TaskCompletionSource<bool>();
        wc.DownloadFileCompleted += (s, e) =>
        {
            if (e.Error != null) tcs.SetException(e.Error);
            else if (e.Cancelled) tcs.SetCanceled();
            else tcs.SetResult(true);
        };
        wc.DownloadFileAsync(new Uri(download), filename);
        // 等待下载完成才会返回,不会提前释放WebClient
        await tcs.Task;
        return result = $"download:{download},filename:{filename}";
    }
    catch (Exception ex)
    {
        throw new Exception("更新出现错误,网络连接失败!" + ex.Message);
    }
}
  1. 推荐替代方案:WebClient已经被微软官方标记为过时类型,优先使用HttpClient实现异步下载,兼容性和稳定性更好:
// HttpClient建议全局声明复用,不要每次请求都新建
private static readonly HttpClient _httpClient = new HttpClient();
public async Task DownloadUpdateAsync(string downloadUrl, string savePath)
{
    using var response = await _httpClient.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
    // 校验请求是否成功
    response.EnsureSuccessStatusCode();
    var totalLength = response.Content.Headers.ContentLength ?? 0;
    using var contentStream = await response.Content.ReadAsStreamAsync();
    using var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
    var buffer = new byte[8192];
    long totalRead = 0;
    int read;
    while ((read = await contentStream.ReadAsync(buffer)) > 0)
    {
        await fileStream.WriteAsync(buffer.AsMemory(0, read));
        totalRead += read;
        if (totalLength > 0)
        {
            // 计算下载进度
            CommonMethod.autostep = (int)((double)totalRead / totalLength * 100);
        }
    }
    isFinish();
}

内容的提问来源于stack exchange,提问作者小确幸

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 07:45:02