net48 SolidWorks插件加载System.Text.Json报程序集加载异常求解
问题背景
- 开发场景:面向.NET Framework 4.8(net48)的SolidWorks C#类库插件,通过
RegAsm.exe /codebase注册为COM组件供SolidWorks加载 - 项目依赖:
com.solidworks.core 29.5.1、com.solidworks.tools 21.5.0、System.Text.Json 6.0.2 - 触发场景:执行
System.Text.Json.JsonDocument.Parse(jsonText)时抛出文件找不到异常 - 异常信息:
Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
已尝试操作与待确认疑问
- 已在csproj中开启自动生成绑定重定向配置:
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
生成的dll.config中已配置System.Runtime.CompilerServices.Unsafe 0.0.0.0-6.0.0.0版本统一重定向到6.0.0.0,但异常仍然存在。
- 项目输出目录
bin\Debug\net48下已存在版本匹配的文件:System.Text.Json.dll(6.0.0.2,清单中引用Unsafe 6.0.0.0)、System.Runtime.CompilerServices.Unsafe.dll(6.0.0.0),需要确认:- CLR加载
System.Text.Json.dll的搜索路径、加载System.Runtime.CompilerServices.Unsafe.dll的搜索路径具体包含哪些位置,是否包含GAC
- CLR加载
- 相同逻辑的独立net48控制台程序运行无异常,确认问题和SolidWorks宿主环境相关
- VS调试模块窗口显示:异常触发前
System.Text.Json 6.0.0.0已经从项目输出目录加载,Unsafe程序集尚未加载,需要确认:- 为什么CLR会尝试加载4.0.4.1版本的Unsafe,而非System.Text.Json清单中引用的6.0.0.0版本
- 4.0.4.1这个版本号的具体来源
根因解析
1. 绑定重定向失效的核心原因
COM加载场景下,CLR默认读取的是宿主进程(也就是SolidWorks.exe)同目录下的SolidWorks.exe.config作为程序集绑定配置文件,不会自动读取插件dll同目录下的插件名.dll.config,这就是配置了绑定重定向却完全不生效的直接原因。
控制台程序能正常运行,是因为控制台程序是进程主入口,CLR会自动读取exe同目录下的xxx.exe.config配置,绑定重定向可以正常生效。
2. 4.0.4.1版本号的来源
这个版本号是SolidWorks进程已经加载的其他依赖项携带的引用:SolidWorks本身以及其预装的大量官方/第三方插件、扩展模块,很多会依赖旧版本的System.Runtime.CompilerServices.Unsafe(4.0.4.1是该库的经典旧版本号,对应4.x系列的正式发行版)。
CLR在net48环境下处理程序集加载请求时,会优先检查当前进程内已经存在的程序集引用版本记录:当加载的System.Text.Json触发Unsafe加载需求时,CLR发现进程内已经有对Unsafe 4.0.4.1版本的引用记录,又因为绑定重定向配置根本没被CLR读取,所以CLR不会做版本重定向,直接尝试加载4.0.4.1版本的Unsafe。
3. CLR程序集搜索路径规则
CLR的程序集加载搜索优先级如下,GAC优先级远高于本地目录:
- 第一步:检查全局程序集缓存(GAC),如果找到匹配版本的程序集直接加载,不会继续搜索本地路径
- 第二步:通过触发加载的程序集的
CodeBase属性确定基础搜索路径:System.Text.Json是从插件输出目录加载的,所以它触发的依赖搜索基础路径是插件输出目录,但注意如果没有对应的绑定配置,CLR只会搜索完全匹配请求版本号的dll,不会自动加载高版本dll - 第三步:依次检查宿主进程目录、系统目录、PATH环境变量包含的目录
本地输出目录里的Unsafe是6.0.0.0版本,和CLR当前请求的4.0.4.1版本号不匹配,所以即使文件存在也不会被识别加载。
可行解决方案
- 方案1(侵入性最低,推荐):在插件代码中订阅
AppDomain.CurrentDomain.AssemblyResolve事件,在事件中手动加载输出目录下的对应版本Unsafe、System.Text.Json等依赖dll,完全绕开默认的绑定逻辑:
// 在插件入口点(比如COM注册的Connect方法最开始位置)注册事件 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var assemblyName = new AssemblyName(args.Name); var dllPath = Path.Combine(Path.GetDirectoryName(typeof(插件入口类).Assembly.Location), $"{assemblyName.Name}.dll"); return File.Exists(dllPath) ? Assembly.LoadFrom(dllPath) : null; };
- 方案2:手动把插件dll.config里的绑定重定向配置,合并到SolidWorks安装目录下的
SolidWorks.exe.config文件中,注意修改前备份原配置,避免影响SolidWorks本身运行。 - 方案3:构建插件时把System.Text.Json相关的所有依赖dll都设置为ILMerge合并到插件单dll中,避免外部依赖搜索。
内容的提问来源于stack exchange,提问作者Kjara

