You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mono环境下将程序集加载至独立AppDomain时触发FileNotFoundException

解决Mono环境下Discord机器人插件AppDomain加载依赖缺失问题

我明白你在macOS上用Mono开发Discord机器人插件系统时遇到的头疼问题——明明主域已经加载了依赖,独立AppDomain却死活找不到这些程序集,各种加载方式都触发FileNotFoundException,还没法实现插件卸载重载。我之前也在类似场景踩过坑,给你几个针对性的解决方案:

1. 给独立AppDomain配置程序集解析回调

这是最关键的一步:Mono下的AppDomain不会自动继承主域的已加载程序集,你需要手动告诉它去哪里找依赖。可以创建一个继承自MarshalByRefObject的程序集解析器,在独立域里注册AppDomain.AssemblyResolve事件,让它优先从主域已加载的程序集中查找,再去指定目录加载:

public class AssemblyResolver : MarshalByRefObject
{
    public void SetupResolver()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            // 先尝试从主域已加载的程序集中匹配
            var currentDomainAssemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var asm in currentDomainAssemblies)
            {
                if (asm.FullName == args.Name)
                {
                    return asm;
                }
            }
            // 主域没有的话,尝试从主程序目录加载
            string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, new AssemblyName(args.Name).Name + ".dll");
            if (File.Exists(assemblyPath))
            {
                return Assembly.LoadFrom(assemblyPath);
            }
            // 最后尝试插件目录
            string pluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "modules");
            assemblyPath = Path.Combine(pluginDir, new AssemblyName(args.Name).Name + ".dll");
            if (File.Exists(assemblyPath))
            {
                return Assembly.LoadFrom(assemblyPath);
            }
            return null;
        };
    }
}

2. 修正你的AppDomain加载流程

你当前直接用domain.Load(byte[])的方式有本质问题:这种加载方式不会触发程序集解析回调,而且Mono下对字节流加载的程序集依赖处理有特殊限制。正确的做法是:

  • 创建AppDomain时指定基础目录和私有bin路径,让它知道去哪里找依赖
  • 在新域中实例化解析器并注册回调
  • 通过程序集名称或路径加载插件,而不是直接传入字节流

修改后的SetupAppDomain方法示例:

private void SetupAppDomain() 
{ 
    string pluginPath = Path.Combine(Directory.GetCurrentDirectory(), "modules"); 
    Console.WriteLine(pluginPath); 
    List<string> installedModules = new List<string>(); 

    foreach(string modulePath in Directory.GetFiles(pluginPath, "*.dll")) 
    { 
        try 
        { 
            // 配置AppDomain的基础路径和私有bin目录
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; // 指向主程序目录,依赖都在这里
            setup.PrivateBinPath = pluginPath; // 让域也能扫描插件目录
            setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

            // 创建独立AppDomain
            AppDomain domain = AppDomain.CreateDomain(
                Path.GetFileNameWithoutExtension(modulePath), 
                AppDomain.CurrentDomain.Evidence, 
                setup
            );

            // 在新域中初始化程序集解析器(必须用CreateInstanceAndUnwrap跨域调用)
            var resolver = (AssemblyResolver)domain.CreateInstanceAndUnwrap(
                typeof(AssemblyResolver).Assembly.FullName,
                typeof(AssemblyResolver).FullName
            );
            resolver.SetupResolver();

            // 通过程序集名称加载插件,触发解析回调处理依赖
            Assembly pluginAssembly = domain.Load(AssemblyName.GetAssemblyName(modulePath));
            installedModules.Add(pluginAssembly.GetName().Name);

            // 后续可以通过CreateInstanceAndUnwrap创建插件实例,实现跨域交互
            // 比如 IPlugin plugin = (IPlugin)domain.CreateInstanceAndUnwrap(pluginAssembly.FullName, "YourPluginClassName");
        } 
        catch(Exception ex) 
        { 
            Console.WriteLine($"加载插件失败: {modulePath}, 错误详情: {ex.Message}\n{ex.StackTrace}");
            // 不要直接throw,避免中断其他插件的加载流程
        } 
    } 
}

3. Mono环境下的额外注意事项

  • 确保你加载的依赖程序集版本和主域完全一致,比如Newtonsoft.Json的版本要匹配,否则会出现版本冲突
  • 避免使用Assembly.Load(byte[])加载依赖,Mono下这种方式会导致程序集无法被解析回调识别
  • 如果你有原生依赖(比如DSharpPlus的某些原生库),需要确保它们的路径能被Mono找到,可以提前设置DYLD_LIBRARY_PATH环境变量指向原生库目录

为什么你的原有方法不行?

你之前尝试的几种方式都没触碰到核心问题:

  • 独立AppDomain和主域是完全隔离的,不会自动共享已加载的程序集
  • 直接加载字节流不会触发AssemblyResolve事件,依赖无法被自动解析
  • 手动按顺序加载时,Mono下加载程序集会严格检查上下文,单独加载Newtonsoft.Json时,它的系统级依赖可能在新域中没有正确初始化

内容的提问来源于stack exchange,提问作者MrMiketheripper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:11:26