通过Roslyn编译的程序集加载时触发FileNotFoundException问题
我之前也踩过Roslyn动态编译依赖加载的坑,你的情况核心问题很明确:Roslyn编译时的MetadataReference只解决了编译阶段的类型引用问题,但运行时CLR并不知道你指定的RazorLight.dll路径,它会默认从GAC、应用程序目录等常规位置查找,找不到就抛出FileNotFoundException。下面是几个实用的解决方案:
1. 挂钩AssemblyResolve事件手动加载依赖
这是最直接有效的办法,当CLR找不到指定程序集时,我们手动从已知路径加载它。你可以在加载Sample.dll或者初始化RazorLight引擎之前添加这段代码:
using System.Reflection; using System; // 注册程序集解析事件 AppDomain.CurrentDomain.AssemblyResolve += (sender, resolveArgs) => { var targetAssemblyName = new AssemblyName(resolveArgs.Name); // 匹配RazorLight程序集(可根据需要精确匹配版本/公钥) if (string.Equals(targetAssemblyName.Name, "RazorLight", StringComparison.OrdinalIgnoreCase)) { // 替换为你实际的RazorLight.dll路径 string razorLightPath = @"C:\Users\favishg\source\repos\Empeon_Reports\Reports\bin\Debug\net461\RazorLight.dll"; return Assembly.LoadFrom(razorLightPath); } // 其他依赖如果也有加载问题,可以在这里继续添加处理逻辑 return null; };
2. 确认RazorLight版本完全匹配
异常提示找不到RazorLight, Version=2.0.0.0,你需要先确认编译时引用的RazorLight.dll版本确实是2.0.0.0:
- 右键RazorLight.dll → 属性 → 详细信息,查看"文件版本"和"产品版本"
- 或者用代码快速验证:
var razorAssembly = Assembly.LoadFrom(@"C:\Users\favishg\source\repos\Empeon_Reports\Reports\bin\Debug\net461\RazorLight.dll"); Console.WriteLine($"RazorLight版本:{razorAssembly.GetName().Version}");
如果版本不匹配,要么更新引用的RazorLight版本,要么在AssemblyResolve事件中用名称匹配(上面的代码已经这么做了,会自动加载你指定路径的版本)。
3. 给编译选项指定CodeBase(进阶)
如果你能直接控制Roslyn的编译过程(比如自定义RazorLight的编译服务),可以在编译选项中设置CodeBase,提前告诉CLR依赖程序集的位置:
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; var compileOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithMetadataImportOptions(MetadataImportOptions.All) // 指定RazorLight的路径作为CodeBase .WithCodeBase(@"C:\Users\favishg\source\repos\Empeon_Reports\Reports\bin\Debug\net461\RazorLight.dll"); // 后续将这个compileOptions传递给RazorLight的编译逻辑
不过这个方法需要你深入RazorLight的编译配置,如果你用的是默认的RazorLightEngineBuilder,可能需要自定义ICompilationService来替换默认实现。
4. 检查RazorLight的依赖链
有时候异常的根源不是RazorLight.dll本身,而是它依赖的其他组件缺失。你可以用Visual Studio的"依赖项"窗口查看RazorLight.dll的依赖,或者用Dependency Walker工具扫描,确保所有依赖都在CLR能找到的路径下,或者同样通过AssemblyResolve事件处理这些依赖。
另外你提到异常触发在调用assembly.GetCustomAttribute<RazorLightTemplateAttribute>()时,这是因为当CLR尝试访问这个特性类型时,才需要实际加载包含该类型的RazorLight程序集——之前的编译阶段只是用MetadataReference获取了类型信息,并没有真正加载程序集。
内容的提问来源于stack exchange,提问作者Saf-G

