为什么直接调用 BITS COM 接口在 C# 中容易失败
因为
IBackgroundCopyManager等 COM 接口未被 .NET 自动封装,直接引用类型库(如
bitsadmin.exe /?提示的旧工具)或尝试
tlbimp生成互操作程序集,常导致
InvalidCastException或
COMException 0x80040154(类未注册)。BITS 的 COM 接口要求严格初始化(单线程套间,STA),且部分方法需管理员权限或特定 Windows 版本支持。 必须在 STA 线程中创建和调用 COM 对象,
Thread.SetApartmentState(ApartmentState.STA)不能事后设置,得在
Thread.Start()前完成 推荐绕过原始 COM,改用
bitsadmin.exe命令行封装或 Windows 10+ 的
Windows.Networking.BackgroundTransferUWP API(需适配桌面桥) 若坚持 COM,应使用
System.Runtime.InteropServices.ComTypes.IConnectionPointContainer手动连接事件,而非依赖 .NET 自动生成的事件包装
用 bitsadmin.exe 封装上传任务最简可行方案
bitsadmin.exe是 Windows 内置命令行工具,无需额外引用,适合后台服务场景。它不提供实时进度回调,但可通过轮询状态 + 退出码判断成败,稳定性远高于直连 COM。 创建任务:
bitsadmin /create /download myjob(下载)或
/upload(上传) 添加文件:
bitsadmin /addfile myjob "C:\local\file.zip" "https://server.com/remote/file.zip"设置凭据(如需):
bitsadmin /setcredentials myjob server BASIC username password开始并等待:
bitsadmin /resume myjob && bitsadmin /info myjob,解析输出中的
STATE:和
ERROR:行 注意:任务名(
myjob)必须全局唯一,服务中建议用 GUID 避免冲突
Windows 10+ 后台传输(BackgroundTransfer)在桌面应用中的限制与绕过
Windows.Networking.BackgroundTransfer是现代替代方案,但默认仅限 UWP 应用。桌面应用(WPF/WinForms)可通过 Desktop Bridge 或
AppContainer模式启用,否则会抛出
UnauthorizedAccessException。 非桥接应用可调用该 API,但仅限“前台”任务;后台服务进程因无 UI 上下文,
CreateUploadAsync会静默失败 若已打包为 MSIX 并声明
rescap:Capability Name="backgroundTransfer",则可在服务中调用,但需确保服务以交互式用户上下文运行(非 LocalSystem) 关键参数:
BackgroundTransferGroup控制并发数,
UploadOperation.SuccessOrFailThresholdForFailureInBytes可设断点续传阈值
服务中使用 BITS 必须处理的三个底层细节
无论选哪种方式,Windows 服务环境对 BITS 有硬性约束:网络凭据、会话隔离、权限提升。
BITS 任务默认绑定到创建它的用户会话;服务若以LocalSystem运行,无法访问用户凭据缓存,需显式调用
bitsadmin /setcredentials或在 COM 中用
IBackgroundCopyJob.AddFileWithRanges配合
IBackgroundCopyJob.SetNotifyFlags从 Windows Vista 起,BITS 不再允许跨会话访问任务,服务中查询其他用户任务会返回
HRESULT 0x80070005(拒绝访问) 上传大文件时,BITS 默认启用 HTTP 1.1 分块编码;若目标服务器不支持(如某些嵌入式 HTTP 服务),需提前用
bitsadmin /sethttpmethod myjob PUT切换为完整体上传
BITS 不是“开箱即用”的后台传输黑盒——它的行为高度依赖 Windows 版本、服务登录身份、目标服务器 HTTP 实现,以及你是否愿意接受命令行封装带来的可观测性折损。
