从零开始实现ASP.NET Core MVC的插件式开发(七) - 近期问题汇总及部分解决方案 (3)

然后我们修改DemoPlugin1的HelloWorld方法,在返回视图之前,发布一个LoadHelloWorldEvent的消息。

[Area("DemoPlugin1")] public class Plugin1Controller : Controller { private INotificationRegister _notificationRegister; public Plugin1Controller(INotificationRegister notificationRegister) { _notificationRegister = notificationRegister; } [Page("Plugin One")] [HttpGet] public IActionResult HelloWorld() { string content = new Demo().SayHello(); ViewBag.Content = content + "; Plugin2 triggered"; _notificationRegister.Publish("LoadHelloWorldEvent", JsonConvert.SerializeObject(new LoadHelloWorldEvent() { Str = "Hello World" })); return View(); } } public class LoadHelloWorldEvent { public string Str { get; set; } } AssemblyLoadContext产生的灵异问题

上面的代码看起来很美好,但是实际运行的时候,你会遇到一个灵异的问题,就是系统不能将DemoPlugin2中的NotificationProvider转换为INotificationProvider接口类型的对象。

从零开始实现ASP.NET Core MVC的插件式开发(七) - 近期问题汇总及部分解决方案

这个问题困扰了我半天,完全想象不出可能的问题,但是我隐约感觉这是一个AssemblyLoadContext引起的问题。

在上一篇中,我们曾经查找过.NET Core的程序集加载设计文档。

在.NET Core的设计文档中,对于程序集加载有这样一段描述

If the assembly was already present in A1's context, either because we had successfully loaded it earlier, or because we failed to load it for some reason, we return the corresponding status (and assembly reference for the success case).

However, if C1 was not found in A1's context, the Load method override in A1's context is invoked.

For Custom LoadContext, this override is an opportunity to load an assembly before the fallback (see below) to Default LoadContext is attempted to resolve the load.

For Default LoadContext, this override always returns null since Default Context cannot override itself.

这里简单来说,意思就是当在一个自定义LoadContext中加载程序集的时候,如果找不到这个程序集,程序会自动去默认LoadContext中查找,如果默认LoadContext中都找不到,就会返回null。

这里我突然想到会不会是因为DemoPlugin1、DemoPlugin2以及主站点的AssemblyLoadContext都加载了Mystique.Core.dll程序集的缘故,虽然他们加载的是同一个程序集,但是因为LoadContext不同,所以系统认为它是2个程序集。

PS: 主站点的AssemblyLoadContext即默认的LoadContext

其实对于DemoPlugin1和DemoPlugin2来说,它们完全没有必须要加载Mystique.Core.dll程序集,因为主站点的默认LoadContext已经加载了此程序集,所以当DemoPlugin1和DemoPlugin2使用Mystique.Core.dll程序集中定义的INotificationProvider时,就会去默认的LoadContext中加载,这样他们加载的程序集就都是默认LoadContext中的了,就不存在差异了。

于是根据这个思路,我修改了一下插件程序集加载部分的代码,将Mystique.Core.*程序集排除在加载列表中。

从零开始实现ASP.NET Core MVC的插件式开发(七) - 近期问题汇总及部分解决方案

重新启动项目之后,项目正常运行,消息发布订阅能正常运行。

从零开始实现ASP.NET Core MVC的插件式开发(七) - 近期问题汇总及部分解决方案

项目后续尝试添加的功能

由于篇幅问题,剩余的其他问题和功能会在下一篇中来完成。以下是项目后续会逐步添加的功能

添加/移除插件后,主站点导航栏自动加载插件入口页面(已完成,下一篇中说明)

在主站点中,添加页面管理模块

尝试一个页面加载多个插件,当前的插件只能实现一个插件一个页面。

不过如果大家如果有什么其他想法,也可以给我留言或者在Github上提Issue,你们的建议就是我进步的动力。

总结

本篇针对前一阵子Github Issue和文档评论中比较集中的问题进行了说明和解答,主要讲解了如何在Visual Studio中调试运行插件以及如何实现插件间的消息传输。后续我会根据反馈,继续添加新内容,大家敬请期待。

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

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