C# 使用Assembly.Load、Assembly.LoadFile为插件正确加载依赖项
我正在开发一个基于插件的框架,该框架允许插件根据某种契约(接口)在彼此之间交换数据 目前,Windows服务可以通过两种方式加载插件: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服务目录(AppDomainBase)
- 插件
- 插件1
- Plugin1.dll
- SharedDependence.dll(1.0.0.0)
- 插件2
- Plugin2.dll
- SharedDependence.dll(1.0.1.0)
- 插件1
- 插件
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的见解?我知道它只加载请求的程序集,没有对依赖项进行额外的探测。