C# 使用Assembly.Load、Assembly.LoadFile为插件正确加载依赖项

C# 使用Assembly.Load、Assembly.LoadFile为插件正确加载依赖项,c#,.net,plugins,.net-assembly,assembly-resolution,C#,.net,Plugins,.net Assembly,Assembly Resolution,我正在开发一个基于插件的框架,该框架允许插件根据某种契约(接口)在彼此之间交换数据 目前,Windows服务可以通过两种方式加载插件: 与托管插件的Windows服务位于同一AppDomain中 在另一个进程中,Windows服务通过命名管道(WCF)与之通信 这在大多数情况下都很有效。但是,在某些情况下,一个插件可能引用程序集,而另一个插件则引用程序集的较新版本。在这种情况下,我总是希望加载较新版本的依赖项,而不管先加载哪个插件 以下是文件夹结构: Windows服务目录(AppDomain

我正在开发一个基于插件的框架,该框架允许插件根据某种契约(接口)在彼此之间交换数据

目前,Windows服务可以通过两种方式加载插件:

  • 与托管插件的Windows服务位于同一AppDomain中
  • 在另一个进程中,Windows服务通过命名管道(WCF)与之通信
  • 这在大多数情况下都很有效。但是,在某些情况下,一个插件可能引用程序集,而另一个插件则引用程序集的较新版本。在这种情况下,我总是希望加载较新版本的依赖项,而不管先加载哪个插件

    以下是文件夹结构:

    • Windows服务目录(AppDomainBase)
      • 插件
        • 插件1
          • Plugin1.dll
          • SharedDependence.dll(1.0.0.0)
        • 插件2
          • Plugin2.dll
          • SharedDependence.dll(1.0.1.0)
    我已经做了很多研究,尝试了很多不同的东西。也就是说:

  • 我无法通过app.config文件重定向程序集绑定。虽然这是可行的,但它并不实用,因为我无法提前知道所有依赖项,也无法将每个依赖项都添加到app.config中
  • 我不能用GAC
  • 我不想加载同一程序集的多个版本,只想加载最新版本
  • 我已经阅读了Assembly.Load、LoadFrom和LoadFile,并尝试使用它们。我仍然不是100%清楚Load和LoadFrom之间的区别。它们似乎都通过从加载目录进行融合和探测,自动加载每个插件的依赖项

    我目前的解决方案是搜索AppDomainBase的所有子目录,以查找并缓存每个插件文件夹中的所有DLL。如果我多次遇到同一个程序集,我总是跟踪最新版本及其位置

    然后,通过调用Assembly.LoadFile加载每个插件,这样fusion就不会加载依赖项。我正在订阅AppDomain.CurrentDomain.AssemblyResolve事件。当引发该事件时,我检查程序集的名称以确定应该加载哪个预缓存的程序集,然后通过调用assembly.load来加载它

     private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            try
            {
                Log(string.Format("Resolving: {0}", args.Name));
    
                // Determine if the assembly is already loaded in the AppDomain. Only the name of the assembly is compared here.
                var asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().FullName.Split(',')[0] == args.Name.Split(',')[0]);
    
                if (asm == null)
                {
                    // The requsted assembly is not loaded in the current AppDomain
                    Log(string.Format("Assembly is not loaded in AppDomain: [{0}]", args.Name));
    
                    // Determine if the assembly is one that has already been found and cached
                    var asmName = _RefCandidates.Find(a => a.Name.FullName.Split(',')[0] == args.Name.Split(',')[0]);
    
                    if (asmName != null)
                    {
                        // The assembly exists in the cache, but has not been loaded. Load it.
                        Log(string.Format("Pre-loaded assembly found in cache. Loading: [{0}], [{1}]", asmName.Name, asmName.Name.CodeBase));
                        return Assembly.LoadFile(asmName.File.FullName);
                    }
                }
                else
                    Log(string.Format("Assembly is already loaded in AppDomain: [{0}], [{1}]", asm.GetName(), asm.GetName().CodeBase));
    
                return asm;
            }
            catch (Exception ex)
            {
                Logger.Write(ex, LogEntryType.Error);
                return null;
            }
        }
    
    首先,完成我需要做的事情的最佳方式是什么,我做错了什么

    其次,如果链中的依赖项希望引用GAC中的某个内容,会发生什么情况?我假设它将不再被找到,因为我正在使用LoadFile并跳过fusion。此外,我还阅读了一些关于序列化不使用LoadFile的内容。具体是什么?资源程序集呢

    此模型假设所有较新版本的依赖程序集都是向后兼容的,因为我将只加载最新版本


    非常感谢您的任何输入。

    如果此程序集的解析未失败,则无法手动加载程序集(只有在这种情况下,才会引发AssemblyResolve)。 因此,你的插件架构不能用Assembly.Load*方法实现

    现在有两条路。
    首先(不推荐):以某种方式删除限制(例如,在开始时使用Assembly.Load,在需要对象的任何位置,搜索CurrentDomain程序集,选择正确的程序集并通过反射构造对象并使用它们)。
    第二(推荐):回顾您最初的问题并寻找解决方案,这可能很容易实现和维护

    看看插件架构提供了什么。
    SharpDevelop的人写信告诉我们他们的插件树。
    找到你的路


    另请参阅此关于程序集加载上下文的内容,以了解为什么assembly.Load With AssemblyResolve事件不起作用。

    我不明白。如果我使用Assembly.LoadFile加载插件,我就能够处理AssemblyResolve事件,因为fusion似乎不用于加载依赖项。这在我上面的例子中似乎有效。实际上,我将上面的代码从使用Assembly.Load更改为Assembly.LoadFile。LoadFile对序列化和资源程序集有哪些其他限制?此外,我似乎能够在AppDomain库的子文件夹中的DLL上使用Assembly.Load方法,并且也会找到并加载它们的依赖项。我想这就是LoadFrom的目的…?这是可行的,因为查找组件的标准程序失败了。AppDomainBase文件夹中没有直接包含SharedDependence.dll,是吗?将SharedDependence.dll放入GAC,您将无法手动解析它。事实上,它看起来已经像地狱了。很抱歉没有回答您的问题,但我想我们在这里处理XY问题,永远不要使用LoadFile(),只使用LoadFrom。来缩小这个问题的范围。谢谢你的链接,很好的信息。然而,您能否提供一些关于为什么永远不应该使用LoadFile的见解?我知道它只加载请求的程序集,没有对依赖项进行额外的探测。