重温.NET下Assembly的加载过程 (3)

PluginDemo.App:插件系统的应用程序。这个程序执行的时候,会扫描程序目录下Modules目录中的DLL,并根据module.xml的Metadata信息,加载相应的插件对象,并执行Initialize方法

PluginDemo.Plugins.Earth:其中的一个插件实现

PluginDemo.Plugins.Mars:另一个插件实现

注意:除了PluginDemo.Common之外的其它三个项目,都对PluginDemo.Common有引用关系。而PluginDemo.App项目仅仅在项目本身依赖于PluginDemo.Plugins.Earth和PluginDemo.Plugins.Mars,它不会去引用这两个项目。目的就是为了当PluginDemo.App被编译时,其余两个插件项目也会同时被编译并输出到指定位置。

在Earth插件的CustomAddIn类中,我们实现了Initialize方法,并在此输出一个字符串:

public class CustomAddIn : AddIn { public override string Name => "Earth AddIn"; public override void Initialize() { Console.WriteLine("Earth Plugin initialized."); } }

在Mars插件的CustomAddIn类中,我们也实现了Initialize方法,并在此输出一个字符串:

public class CustomAddIn : AddIn { public override string Name => "Mars AddIn"; public override void Initialize() { Console.WriteLine("Mars AddIn initialized."); } }

那么,在插件系统主程序中,就会扫描Modules子目录下的module.xml文件,然后解析每个module.xml文件获得每个插件类的Assembly Qualified Name,然后通过Type.GetType方法获得插件类,进而创建实例、调用Initialize方法。代码如下:

static void Main() { var directory = new DirectoryInfo("Modules"); foreach(var file in directory.EnumerateFiles("module.xml", SearchOption.AllDirectories)) { var addinDefinition = AddInDefinition.ReadFromFile(file.FullName); var addInType = Type.GetType(addinDefinition.FullName); var addIn = (AddIn)Activator.CreateInstance(addInType); Console.WriteLine($"{addIn.Id} - {addIn.Name}"); addIn.Initialize(); } }

接下来,修改App.config文件,修改为:

<?xml version="1.0" encoding="utf-8" ?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="Modules\Earth;Modules\Mars;" /> </assemblyBinding> </runtime> </configuration>

此时,运行程序,可以得到:

image

目前没有什么问题。接下来,对两个AddIn分别做一些修改。让这两个AddIn依赖于不同版本的Newtonsoft.Json,比如,Earth依赖于7.0.0.0的版本,Mars依赖于6.0.0.0的版本,然后分别修改两个CustomAddIn的Initialize方法,在方法中各自调用一次JsonConvert.SerializeObject方法,以触发Newtonsoft.Json这个Assembly的加载。此时再次运行程序,你将看到下面的异常:

image

现在,刷新fuslogvw.exe,找到Newtonsoft.Json的日志:

image

双击打开日志,可以看到如下信息:

image

从整个过程可以看出:

PluginDemo.App.exe正在试图加载PluginDemo.Plugins.Mars Assembly

PluginDemo.Plugins.Mars开始调用Newtonsoft.Json

扫描应用程序配置文件、Host配置文件以及machine.config文件,均无找到Newtonsoft.Json的重定向信息,此时,Newtonsoft.Json版本确定为6.0.0.0

GAC扫描失败,继续查找文件

首先查找应用程序当前目录下有没有Newtonsoft.Json,以及Newtonsoft.Json子目录下有没有Newtonsoft.Json.dll,发现都没有,继续

然后,通过App.config中的probing的privatePath设定,首先查找Modules\Earth目录(因为这个目录放在privatePath的第一个),找到了一个叫做Newtonsoft.Json.dll的Assembly,于是,判断版本是否相同。结果,找到的是7.0.0.0,而它需要的却是6.0.0.0,版本不匹配,于是就抛出异常,退出程序

那么接下来,改一改App.config文件,将privatePath下的两个值换个位置呢?

image

再试试:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdfzw.html