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

使用WebClient下载文件触发TargetInvocationException异常求助

VB.NET异步下载文件异常问题排查与修复

我最近写了一段VB.NET代码,用来从指定URL下载更新包,文件确实能成功保存到本地,但每次下载完成都会抛出System.Reflection.TargetInvocationException异常,而且DownloadFileCompleted方法完全没触发,实在搞不懂哪里出问题了!

先贴一下我原来的代码:

Private Sub getPatch()
    Using client As New WebClient
        Dim url As String = My.Settings.host & "/update.zip"
        If Directory.Exists(Replace(fName, "\update.zip", "")) Then
            Directory.Delete(Replace(fName, "\update.zip", ""), True)
        End If
        Directory.CreateDirectory(Replace(fName, "\update.zip", ""))
        AddHandler client.DownloadProgressChanged, AddressOf ProgressChanged
        AddHandler client.DownloadFileCompleted, AddressOf DownloadFileCompleted
        client.DownloadFileAsync(New Uri(url), fName)
    End Using
End Sub

Public Sub ProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs)
    Try
        If e.ProgressPercentage = 100 Then Exit Sub
        ProgressBar1.Value = e.ProgressPercentage
    Catch ex As Exception
        MsgBox(ex.ToString)
    End Try
End Sub

Public Sub DownloadFileCompleted(ByVal sender As Object, ByVal e As System.Net.DownloadDataCompletedEventArgs)
    If Not e.Cancelled AndAlso e.Error Is Nothing Then
        MessageBox.Show("Download success")
        extractZip(fName)
    Else
        MessageBox.Show("Download failed")
    End If
End Sub

抛出的异常信息是:

An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
Additional information: Exception has been thrown by the target of an invocation.

问题根源分析

我仔细排查后发现两个关键错误:

  1. 事件处理方法参数类型不匹配
    WebClient.DownloadFileCompleted事件对应的参数类型是System.ComponentModel.AsyncCompletedEventArgs,但我写的DownloadFileCompleted方法用了System.Net.DownloadDataCompletedEventArgs——这个类型是给DownloadDataAsync事件用的!参数类型不匹配导致.NET反射调用事件处理方法时失败,直接抛出了TargetInvocationException,这也是为什么方法根本没触发的原因。

  2. WebClient被提前释放
    原来的代码把WebClient放在Using块里,getPatch方法执行完毕后,Using块会立即Dispose掉WebClient,但异步下载操作此时还在后台运行。Client被提前释放后,后续的事件通知完全无法正常执行,进一步加剧了异常问题。

修正后的代码

针对这两个问题,我调整了代码结构,修复后的版本如下:

' 将WebClient声明为类级变量,避免提前被释放
Private client As WebClient

Private Sub getPatch()
    client = New WebClient()
    Dim url As String = My.Settings.host & "/update.zip"
    Dim targetDir As String = Replace(fName, "\update.zip", "")
    
    ' 清理并创建目标目录(提取变量让代码更清晰)
    If Directory.Exists(targetDir) Then
        Directory.Delete(targetDir, True)
    End If
    Directory.CreateDirectory(targetDir)
    
    ' 绑定事件处理方法
    AddHandler client.DownloadProgressChanged, AddressOf ProgressChanged
    AddHandler client.DownloadFileCompleted, AddressOf DownloadFileCompleted
    
    ' 启动异步下载
    client.DownloadFileAsync(New Uri(url), fName)
End Sub

Public Sub ProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs)
    Try
        If e.ProgressPercentage = 100 Then Exit Sub
        ProgressBar1.Value = e.ProgressPercentage
    Catch ex As Exception
        MsgBox(ex.ToString)
    End Try
End Sub

Public Sub DownloadFileCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
    ' 下载完成后手动释放WebClient,避免内存泄漏
    Try
        If Not e.Cancelled AndAlso e.Error Is Nothing Then
            MessageBox.Show("Download success")
            extractZip(fName)
        Else
            ' 更友好的错误提示,区分取消和错误情况
            Dim errorMsg As String = If(e.Error IsNot Nothing, $"Error: {e.Error.Message}", "Download cancelled by user")
            MessageBox.Show($"Download failed: {errorMsg}")
        End If
    Finally
        If client IsNot Nothing Then
            ' 先移除事件处理,再释放资源
            RemoveHandler client.DownloadProgressChanged, AddressOf ProgressChanged
            RemoveHandler client.DownloadFileCompleted, AddressOf DownloadFileCompleted
            client.Dispose()
            client = Nothing
        End If
    End Try
End Sub

修正点说明

  • 把WebClient提升为类级变量,避免Using块提前释放它,确保异步下载全程client都处于可用状态。
  • 修正DownloadFileCompleted的参数类型为System.ComponentModel.AsyncCompletedEventArgs,和事件委托类型完全匹配,保证事件能正常触发。
  • 在DownloadFileCompleted的Finally块里手动移除事件处理并释放WebClient,避免内存泄漏,同时确保资源被正确清理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:40:23