MystiqueStartup.cs
public static void MystiqueSetup(this IServiceCollection services, IConfiguration configuration) { ... services.AddSingleton<IReferenceContainer, DefaultReferenceContainer>(); services.AddSingleton<IReferenceLoader, DefaultReferenceLoader>(); ... var mvcBuilder = services.AddMvc(); var provider = services.BuildServiceProvider(); using (var scope = provider.CreateScope()) { ... foreach (var plugin in allEnabledPlugins) { ... using (var fs = new FileStream(filePath, FileMode.Open)) { var assembly = context.LoadFromStream(fs); loader.LoadStreamsIntoContext(context, referenceFolderPath, assembly); ... } } } ... }MvcModuleSetup.cs
public void EnableModule(string moduleName) { if (!PluginsLoadContexts.Any(moduleName)) { ... using (var fs = new FileStream(filePath, FileMode.Open)) { var assembly = context.LoadFromStream(fs); _referenceLoader.LoadStreamsIntoContext(context, referenceFolderPath, assembly); ... } } else { ... } ResetControllActions(); }完成代码之后,为了检验效果,我创建了另外一个插件DemoPlugin2, 这个项目的代码和DemoPlugin1基本一样。程序启动时,你会发现DemoPlugin2所使用的引用程序集都是从缓存中加载的,而且DemoPlugin2的路由也能正常访问。
添加页面来显示加载的第三方程序集这里为了显示一下系统中加载了哪些程序集,我添加了一个新页面Assembilies, 这个页面就是调用了IReferenceContainer接口中定义的GetAll方法,显示了静态字典中,所有加载的程序集。
效果如下:
几个测试场景最后,在编写完成以上代码功能之后,我们使用以下几种场景来测试一下,看一看AssemblyLoadContext为我们提供的强大功能。
场景12个插件,一个引用DemoReferenceLibrary的1.0.0.0版本,另外一个引用DemoReferenceLibrary的1.0.1.0版本。其中1.0.0.0版本,SayHello方法返回的字符串是"Hello World. Version 1", 1.0.1.0版本, SayHello方法返回的字符串是“Hello World. Version 2”。
启动项目,安装插件1和插件2,分别运行插件1和插件2的路由,你会得到不同的结果。这说明AssemblyLoadContext为我们做了很好的隔离,插件1和插件2虽然引用了相同插件的不同版本,但是互相之间完全没有影响。
场景2当2个插件使用了相同的第三方库,并加载完成之后,禁用插件1。虽然他们引用的程序集相同,但是你会发现插件2还是能够正常访问,这说明插件1的AssemblyLoadContext的释放,对插件2的AssemblyLoadContext完全没有影响。
总结本篇我为大家介绍了如何解决插件引用程序集的加载问题,这里我们讲解了两种方式,原始方式和缓存方式。这两种方式的最终效果虽然相同,但是缓存方式的效率明显更高。后续我会根据反馈,继续添加新内容,大家敬请期待。