如何引用Roslyn动态生成的程序集?重运行时抛出异常
解决Roslyn动态生成程序集重启后加载失败的问题
这个问题我之前帮好几个开发者排查过,核心原因大多是程序集加载上下文不匹配或者生成路径没被CLR正确识别,下面给你拆解几个靠谱的解决方案:
一、先排查基础路径问题
首先确认你生成的dll和pdb文件确实在指定的tempDir路径里,而且重启应用后这个目录没被系统清理(比如系统临时目录经常会在进程退出后自动删文件)。手动去路径下看看文件是否存在,权限是不是正常——有时候系统权限会导致CLR读不到文件。
二、用正确的姿势加载程序集
重启后动态生成的程序集不在CLR默认的探测路径里,直接Assembly.Load("RunTimeRules.XRefRule")肯定会失败,试试这两种方法:
1. 直接通过文件路径加载
最稳妥的方式就是指定完整路径加载:
var assemblyPath = Path.Combine(tempDir, "RunTimeRules.XRefRule.dll"); var assembly = Assembly.LoadFrom(assemblyPath);
注意LoadFrom会把程序集加载到专属的加载上下文里,如果你的动态程序集还有其他依赖,得确保依赖项也能被找到(比如放在同一个目录)。
2. 订阅程序集解析事件
如果没法硬编码路径,可以给当前AppDomain加个解析事件,当CLR找不到程序集时,手动从你的生成目录加载:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var assemblyName = new AssemblyName(args.Name); var assemblyPath = Path.Combine(tempDir, $"{assemblyName.Name}.dll"); if (File.Exists(assemblyPath)) { return Assembly.LoadFrom(assemblyPath); } return null; };
这样不管什么时候需要加载这个动态程序集,CLR都会触发这个事件,你就能在里面指定加载路径了。
三、生成程序集时的细节优化
用Roslyn的compilation.Emit时,这几个细节能避免后续加载踩坑:
- 确保生成的程序集名称和你后续加载时用的完全一致(包括大小写,Linux/macOS环境下路径是区分大小写的)
- 如果动态程序集依赖其他程序集,编译时一定要把这些依赖加入到
compilation的引用中,比如:
var compilation = CSharpCompilation.Create("RunTimeRules.XRefRule") .WithReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) // 加上你需要的其他依赖引用 .WithSyntaxTrees(yourSyntaxTree);
这样生成的程序集才不会有依赖缺失,重启加载时就不会因为找不到依赖报错了。
四、避开临时目录的坑
如果你用的是Path.GetTempPath()这类系统临时目录,要注意很多系统会在进程退出后自动清理临时文件。建议把生成的程序集放到应用专属的持久化目录,比如:
var appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); var assemblyDir = Path.Combine(appDataDir, "YourAppName", "DynamicAssemblies"); Directory.CreateDirectory(assemblyDir); // 确保目录存在,不存在就创建
这样程序退出后文件不会被自动删掉,重启时也能正常读取。
内容的提问来源于stack exchange,提问作者Gopi
相关产品推荐
相关产品推荐

