Jenkins环境下使用Mono.Cecil解析程序集失败问题求助
问题:Mono.Cecil在Jenkins执行单元测试时解析ASource程序集失败,本地运行正常
场景说明
解决方案包含三个程序集:
- ASource:包含待测试类
MyClass,该程序集引用了其他第三方/内部程序集 - ATest:基于NUnit编写的单元测试项目,测试ASource中的
MyClass - ATestUtils:引用Mono.Cecil,提供通过Type获取类型属性的工具方法
ATestUtils核心代码
// In ATestUtils public static IEnumerable<PropertyDefinition> GetPropertiesFromType(Type typeOfClass) { var ass = AssemblyDefinition.ReadAssembly(typeOfClass.Assembly.Location); var refs = ass.MainModule.ImportReference(typeOfClass); var typeDef = refs.Resolve(); return typeDef.Properties; }
错误信息
Jenkins执行测试时抛出异常:
Error : ATest.MyUnitTestClass.MyUnitTest Mono.Cecil.AssemblyResolutionException : Failed to resolve assembly: 'ASource, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' bei Mono.Cecil.BaseAssemblyResolver.Resolve(AssemblyNameReference name, ReaderParameters parameters) in C:\src\cecil\Mono.Cecil\BaseAssemblyResolver.cs:Zeile 122. bei Mono.Cecil.BaseAssemblyResolver.Resolve(AssemblyNameReference name) in C:\src\cecil\Mono.Cecil\BaseAssemblyResolver.cs:Zeile 117. bei Mono.Cecil.DefaultAssemblyResolver.Resolve(AssemblyNameReference name) in C:\src\cecil\Mono.Cecil\DefaultAssemblyResolver.cs:Zeile 33. bei Mono.Cecil.MetadataResolver.Resolve(TypeReference type) in C:\src\cecil\Mono.Cecil\MetadataResolver.cs:Zeile 110. bei Mono.Cecil.ModuleDefinition.Resolve(TypeReference type) in C:\src\cecil\Mono.Cecil\ModuleDefinition.cs:Zeile 748. bei Mono.Cecil.TypeReference.Resolve() in C:\src\cecil\Mono.Cecil\TypeReference.cs:Zeile 280. bei ATestUtils.TestTools.GetPropertiesFromType(Type typeOfClass) in D:\Hudson\workspace\MyBranchName\MyProject\ATestUtils\TestTools.cs:Zeile 47. bei ATest.MyUnitTestClass.MyUnitTest()
已确认Jenkins环境中typeOfClass.Assembly.Location对应的ASource.dll文件存在,需解答:
- 是否因ASource依赖其他程序集导致加载失败?
- 若需加载依赖应如何操作?
- 为何本地运行正常?
环境信息
- Visual Studio 2022 v17.6.3
- Mono.Cecil v0.11.5
- NUnit v3.13.3
- NUnit3TestAdapter v4.5.0
- Jenkins v2.401.1(Windows10.amd64),通过Pipeline脚本执行PowerShell命令,调用NUnit.Console 3.12.0和opencover.4.7.1221
解答
1. 是否因ASource依赖其他程序集导致加载失败?
是。Mono.Cecil的默认解析器在尝试解析类型时,需要找到ASource的所有依赖程序集。本地环境中,依赖程序集通常和ASource.dll在同一输出目录,或已被GAC、系统路径缓存;但Jenkins的构建输出结构可能不同,依赖程序集不在Mono.Cecil默认搜索路径内,导致解析ASource时无法找到其依赖,进而抛出异常。
2. 如何正确加载依赖程序集?
需要给Mono.Cecil的DefaultAssemblyResolver添加ASource及其依赖所在的目录,让解析器能找到所有需要的程序集。修改后的代码如下:
public static IEnumerable<PropertyDefinition> GetPropertiesFromType(Type typeOfClass) { var assemblyPath = typeOfClass.Assembly.Location; var assemblyDir = Path.GetDirectoryName(assemblyPath); // 创建自定义解析器,添加依赖目录 var resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(assemblyDir); // 读取程序集时指定解析器 var readerParams = new ReaderParameters { AssemblyResolver = resolver, ReadWrite = false }; var ass = AssemblyDefinition.ReadAssembly(assemblyPath, readerParams); var typeDef = ass.MainModule.GetType(typeOfClass.FullName); // 直接从当前模块获取类型定义,避免额外解析步骤 return typeDef?.Properties ?? Enumerable.Empty<PropertyDefinition>(); }
关键修改点:
- 显式创建
DefaultAssemblyResolver,并添加ASource所在目录到搜索路径,确保依赖程序集能被找到 - 读取程序集时传入包含自定义解析器的
ReaderParameters - 直接通过
MainModule.GetType获取类型定义,避免ImportReference+Resolve的额外解析步骤,减少依赖解析触发的概率
如果ASource的依赖分散在多个目录,可通过resolver.AddSearchDirectory()逐个添加这些目录。
3. 为何本地运行正常?
本地运行时,Visual Studio的测试运行环境会将所有依赖程序集复制到测试输出目录(如bin/Debug),ASource.dll和它的依赖在同一目录下;同时本地系统的GAC、环境变量PATH可能包含依赖程序集的路径,Mono.Cecil的默认解析器能自动找到这些位置的程序集。
而Jenkins环境中可能存在以下差异:
- 构建脚本未将ASource的依赖程序集复制到测试执行目录
- Jenkins工作目录结构与本地不同,依赖程序集不在默认搜索路径内
- OpenCover或NUnit.Console的执行上下文,程序集搜索路径与本地Visual Studio测试环境不一致
内容的提问来源于stack exchange,提问作者BNB
相关产品推荐
相关产品推荐

