应用项目运行报Could not load file or assembly 引用项目测试正常
问题背景
当前项目存在四级依赖结构:
- 顶层类库:ClickOnceApplicationDeployment
- 顶层类库直接引用中间层类库:WpfSettings
- 中间层类库原依赖第三方NuGet包:Syroot.KnownFolders
- 最上层为可执行应用,分为两类:类库自带的TestApp测试程序、自行开发的业务应用
前两个类库均附带极简WPF测试窗口,用于验证类库功能,本地测试运行完全正常。由于中间层WpfSettings从未发布官方NuGet包,此前通过修改顶层类库的构建配置,将所有关联依赖DLL统一打包进顶层类库生成的NuGet包中,该方案之前可正常使用。
故障现象
自行开发的业务应用引用顶层类库NuGet包,调用类库静态方法时抛出如下文件找不到异常:
System.IO.FileNotFoundException: 'Could not load file or assembly 'Syroot.KnownFolders, Version=1.2.3.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.'
报错缺失的是中间层类库的依赖项,触发异常的调用代码如下:
RFBApplicationDeployment.ClickOnceApplicationDeployment.SetupEntryApplication(@"P:\MyPublishPath");
异常在进入方法内部逻辑前触发,无法单步调试:该静态方法调用时会先执行类构造函数,调用KnownFolders相关逻辑的代码位于构造函数内,但调试时根本无法进入构造函数就直接抛出异常。
同属最上层可执行层级的类库自带TestApp,调用类库时完全正常,仅自行开发的业务应用存在该加载错误。
已尝试的无效操作
- 累计重启Visual Studio约50次
- 移除Syroot.KnownFolders NuGet引用,替换为微软官方提供的KnownFolders程序集
- 移除所有KnownFolders相关外部引用,直接将对应源码集成到中间层项目中,将外部依赖改为项目内部代码
- 拉取KnownFolders开源仓库源码,为上下游项目直接添加项目引用,不再使用NuGet引用
- 编译时手动将报错DLL复制到业务应用的输出目录(与其他生成DLL同路径)
- 反复执行项目清理、重新生成操作,次数已无法统计
以上操作全部无效,哪怕完全移除对应NuGet包/项目引用,运行时依然会抛出无法加载Syroot.KnownFolders程序集的异常。
排查解决步骤
按以下优先级逐一排查,可定位根因:
- 首先清除本地NuGet幽灵缓存
绝大多数改了代码、删了引用还是报旧依赖错误的问题,都是本地NuGet缓存导致的。打开命令行执行以下命令清空所有本地NuGet缓存:
同时删除所有相关项目(类库、测试项目、业务应用)下的dotnet nuget locals all --clearbin、obj文件夹,卸载业务应用中引用的ClickOnceApplicationDeployment包,重新打包类库时必须升级版本号,再重新安装到业务项目中。如果不升级版本号,VS会优先使用本地缓存的旧版本包,你对类库做的所有修改都不会生效。 - 检查NuGet包的打包配置
你之前将依赖DLL直接打包进NuGet包的方案,必须满足两个配置要求:- 所有依赖DLL必须放在包内对应目标框架的
lib/<目标框架名字对象>/路径下,不能放在包根目录或其他自定义路径,否则引用包的项目不会将这些DLL拷贝到输出目录 - 检查生成NuGet包对应的
.nuspec文件,删除残留的Syroot.KnownFolders依赖节点。如果这里残留了依赖配置,哪怕你已经把KnownFolders的源码完全集成进中间层,CLR加载类库时还是会按程序集元数据的记录去寻找对应版本的Syroot.KnownFolders程序集。
- 所有依赖DLL必须放在包内对应目标框架的
- 检查业务应用的项目生成配置
打开业务应用的项目文件(.csproj),确认两个配置:- 没有设置
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>,该配置开启后所有传递依赖的DLL都不会被拷贝到输出目录 - 顶层类库的引用节点上没有设置
<ExcludeAssets>all</ExcludeAssets>,该配置会阻止引用项的依赖项被拷贝到输出目录
- 没有设置
- 用程序集绑定日志工具定位实际加载路径
打开随Visual Studio安装的fuslogvw.exe(程序集绑定日志查看器),开启绑定日志监控,复现异常后查看对应日志,日志会明确记录CLR搜索目标程序集的所有路径、搜索的程序集版本、加载失败的具体原因,不需要靠猜。90%的程序集加载问题通过该日志可以直接定位根因,常见原因包括:手动复制的DLL版本不匹配、CLR搜索的路径不是你预期的输出目录、GAC中存在同名旧版本程序集被优先加载。 - 测试项目正常的核心原因
类库自带的TestApp是通过项目引用方式直接关联上下游类库,项目引用会自动处理所有依赖的拷贝逻辑;但业务应用是通过NuGet包引用顶层类库,一旦NuGet包的路径、依赖配置错误,就不会自动拷贝传递依赖,这是两种引用方式的核心差异。
内容的提问来源于stack exchange,提问作者RFBomb
相关产品推荐
相关产品推荐

