.NET Conf 2020 - 基于ASP.NET Core构建可热插拔的插件化系统

文章标题:.NET Conf 2020 - 基于ASP.NET Core构建可热插拔的插件化系统

作者:Lamond Lu

项目地址:https://github.com/lamondlu/CoolCat

博客:http://www.cnblogs.com/lwqlun

以下是2020.12.19日的演讲文稿和视频:

大家好,我是陆楠,我来自北京盛安德科技发展有限公司青岛分公司,很高兴能参加本次.NET开发者大会,今天我分享的主题是《基于ASP.NET Core构建可热插拔的插件化系统》。

插件化架构,又称微核架构,指的是软件的内核相对较小,主要功能和业务逻辑都通过插件实现的架构。

插件化架构一般有两个核心概念:

  • 内核

  • 插件

内核通常只包含系统运行的最小功能,以及定义插件必须符合的接口;插件则是互相独立的模块,一般只包含单一的功能。

插件化技术并不是一个新兴的技术,早期很多基于COM开发的WIN32程序其实都是插件化的系统。在.NET/.NET Core中,也有许多插件化的实现方案,例如,开源框架ABP, 开源的内容管理系统DotNetNuke, 电子商务框架NopCommerce。

在设计插件化方案的时候,我们需要考虑以下几个问题:

  • 如何隔离插件

  • 如何实现插件之间的通讯

  • 如何实现热插拔

在.NET Framework时代,我们最常用的方案是使用AppDomain应用程序域来封装插件。使用AppDomain, 我们可以将不同的插件隔离在不同的应用程序域中。至于插件与插件之间的通讯,我们可以借助MarshalByRefObject类来实现。至于热插拔,我们可以通过AppDomain自带的Load/Unload方法来完成,非常的简单。

但是到了.NET Core中,情况大不相同了。主要的原因是.NET Core中已经将AppDomain的概念移除了,那么我们该如何实现插件化呢?

这里我们首先要介绍的是ASP.NET Core中新引入的功能AssemblyLoadContext, 简称ALC, ALC提供了一个类似AppDomain的隔离区域,你可以通过ALC来加载程序集,每个ALC加载的程序集之间互不干扰。

这里请注意,正是由于这种设计,如果将一个程序集引入到两个不同ALC中,运行时会认为他们是不同的程序集。

除了自定义的ALC, 在每个ASP.NET Core应用启动的时候,运行时都会创建一个默认的ALC, 这里我们需要了解自定义ALC和默认ALC的加载顺序

  • 当自定义ALC中的某个插件使用某个程序集的时候,会优先查找当前插件所在的自定义的ALC,如果找不到该程序集,则会进一步查找默认ALC, 所以ALC的程序集加载会优先于默认ALC

我们前面说过,不同的ALC应用相同的程序集,运行时会认为他们是不同的程序集,所以当两个插件使用相同程序集的,我们最好将这个程序集加载到默认ALC中,否则在插件交互的时候可能会出现类型冲突。

除了AssemblyLoadContext, 为了实现插件化,微软在ASP.NET Core中还提供了另外一个高级特性Application Part - 应用组件。

Application Part并不算一个新特性,因为在它在.NET Core 2.x版本中就已经被引入了,但是可能部分开发人员没有过或了解过它。Application Part为ASP.NET Core提供了强大的复用能力,使用Application Part, ASP.NET Core可以从程序集中发现控制器、视图组件、Razor预编译视图、Tag Helper等功能,再借助Application Part Manager, 这些已经编译好的功能组件就可以在其它项目中直接复用了,这就极大提高了ASP.NET Core功能组件的可复用行。

基于AssemblyLoadContextApplication Part, 你就可以轻松的实现ASP.NET Core的插件化了,但是如果想要在ASP.NET Core中实现一个可热插拔的插件化组件系统,我们还需要针对ASP.NET Core解决很多适配性问题,例如:

  • 如果在运行时加载预编译视图?

  • 如果在运行时刷新路由和Controler/Action的映射关系?

  • 一个组件如何从另外一个组件拉取数据

  • 一个组件如何向另外一个组件发送消息通知,完成进一步的业务操作

为了简化这一部分的复杂度,我搭建了一个开源项目CoolCat, CoolCat默认支持.NET Core 3.1和.NET 5。

CoolCat已经实现了以下的特性

  • 插件的安装升级

  • 运行时热插拔插件

  • 插件间通讯

  • 类Swagger的插件文档

  • 支持容器化

以下是CoolCat的整体架构图:

这里主程序为CoolCat, 所有的插件都通过ALC加载到主程序中,主程序中定义了通知中心、文档中心、查询中心

  • 通知中心负责跨插件的消息通知

  • 文档中心负责生成插件的文档

  • 查询中心负责跨插件的数据查询

并且为了简化创建插件项目,我创建了一个CoolCat插件模板,你可以通过dotnet new命令来安装插件模板,并安装模板项目。

dotnet new –i CoolCatModule
dotnet new CoolCatModule –n {projectName}

这里创建出的插件项目和一个普通MVC项目相差无几,比较特殊的是项目会自动生成一个plugin.json文件,里面包含了当前插件的基本信息。

如果这个项目的生成文件打包,那么它就是一个可移动的插件安装包了。

下面呢,我们就通过一个简单的Demo, 给大家演示一下CoolCat项目的基本功能。

这里我们首先使用dotnet run命令启动当前CoolCat, 当程序第一次启动的时候,会自动建表。这里呢,我使用了FluentMigrator作为数据库迁移工具,所以在项目启动时,可以进行自动的脚本迁移。

项目启动之后,我们就可以从浏览器打开这个项目了。项目的默认界面是安装界面,我们可以在这个界面上选择一些预定义的插件,完成安装

当然也不仅限于此,如果你想自定义一个其他的预安装插件,你可以将这些插件放置在项目下的PresetModules目录中。

这里呢,我们就选择默认的2个插件,完成安装。

安装完成之后,我们就会自动进入CoolCat的主界面。这里我们可以通过System菜单下的Plugins子菜单来管理插件。

现在呢,我们来模拟一个场景,假设我们当前开发了2个插件,一个是图书库存插件,一个是图书租借插件。租借插件的数据来源是库存插件。并且当某本图书从租借插件租出之后,库存插件中的当前图书的状态也应该变为出库状态。

这里我们首先通过CoolCat来安装这2个插件。安装完成之后,我们启用插件,这里大家会发现,当我们启动插件之后,顶部导航栏中会自动出现这个插件的菜单,这说明我们的热插拔功能正确的引导并加载的插件。

下一步,我们进入库存插件,添加一本图书C#, 添加完成之后,我们会发现这本书的默认状态是入库状态。

现在我们打开图书租借功能,我们会发现入库状态的图书,正确的显示在了可租借图书列表界面,这说明我们的跨插件拉取数据成功。

这时候,我们选择租出这本书,点击Rent按钮,操作完成之后,这本书就从可租借列表中消失了。

下面我们回到图书库存插件,你会发现图书库存的状态已经变为出库,这是说明我们的跨插件消息传输成功了,当图书租出之后,后续的出库操作自动完成。

至此,我们就完成了这个简单的Demo

如果大家感兴趣的话,可以下载CoolCat项目自行体验一下,针对整个框架的研究过程和其中遇到的问题,我都写在了我的博客园站点中,大家可以自行查看。如果遇到问题或者想参与到本项目中,可以给我发邮件,也可以在博客园给我留言。

以上就是我今天分享的全部内容,谢谢大家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/306215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多款主流编程语言,哪款开发软件最安全?

喜欢就关注我们吧!在当下的市场环境中,除了掌握困扰软件的最常见安全问题外,开发人员还应该了解到底是什么问题在影响他们正在使用的编程语言。静态代码分析安全公司 Veracode 最近发布了一份年度软件安全状态(SOSS)报…

2020年终回顾:时间会回答成长,成长会回答梦想

前言2020年是脚踏实地,慢慢成长的一年,由于疫情的缘故,今年社区没有像去年一样举办多场线下活动,不过 .NET CONF CHINA 大会昨天也在苏州顺利召开,回顾这一年,也有不少惊喜与感悟2020年回顾公众号自从去年双…

java servlet 跳转_Servlet跳转方式sendReDirect()和forward()

在web应用服务中,经常会面对不同SERVLET之间的跳转,目前我们可以通过以下两种方式实现:1.RequestDispatcher.forward()2.ServletResponse.sendReDirect()两者的区别:1.redirect 方式可以跨应用访问,forward 只能在同一个应用中跳转…

明天面腾讯,我刷了这71道面试题...

激动人心的Conf 2020中国.NET开发者大会完美落幕,有幸去到现场,跟诸位.NET大佬、微软大咖、MVP面对面交流,内心很是鸡冻!聊天中我注意到一个细节,很多公司的项目都在逐步用MySQL替换SQLServer,尤其是微服务…

java字符串切分_Java字符串分割(转)

java.lang.String的split()方法, JDK 1.4 or laterpublic String[] split(String regex,int limit)示例代码public class StringSplit {public static void main(String[] args) {String sourceStr "1,2,3,4,5";String[] sourceStrArray sourceStr.split(",&q…

面试官:. NET5源码里用到了哪些设计模式?懵!

作为微软最早迈向开源的重要软件之一,.NET 5的发布具有重要意义!微软希望 .NET Framework 开发者能够迁移他们的代码和应用到 .NET 5.0 上,为明年发布的 .NET 6.0 将 Xamarin 开发者过渡到统一平台奠定基础。版本发布时间轴:.NET …

C# 中 ConcurrentDictionary 一定线程安全吗?

根据 .NET 官方文档的定义&#xff1a;ConcurrentDictionary<TKey,TValue> Class 表示可由多个线程同时访问的线程安全的键/值对集合。这也是我们在并发任务中比较常用的一个类型&#xff0c;但它真的是绝对线程安全的吗&#xff1f;仔细阅读官方文档&#xff0c;我们会发…

2020 .NET 开发者峰会顺利在苏州落幕,相关数据很喜人以及线上直播回看汇总

在2019年上海中国.NET开发者大会的基础上&#xff0c;2020年12月19-20日 继续以“开源、共享、创新” 为主题的第二届中国 .NET 开发者峰会&#xff08;.NET Conf China 2020&#xff09;在苏州人工智能智能产业创新中心落下帷幕&#xff0c;本次大会以线下城市苏州为中心&…

.NET 云原生架构师训练营(模块二 基础巩固 REST RESTful)--学习笔记

2.3.1 Web API -- REST && RESTful什么是 REST&#xff0c;什么是 RESTfulRESTful API 设计RESTful 成熟度模型什么是 REST&#xff0c;什么是 RESTful理解RESTful架构&#xff1a;https://www.ruanyifeng.com/blog/2011/09/restful.htmlREST&#xff08;Representatio…

vue 一个组件内多个弹窗_论如何用Vue实现一个弹窗-一个简单的组件实现

前言最近在使用element-ui框架&#xff0c;用到了Dialog对话框组件&#xff0c;大致实现的效果&#xff0c;跟我之前自己在移动端项目里面弄的一个弹窗组件差不太多。然后就想着把这种弹窗组件的实现方式与大家分享一下&#xff0c;下面本文会带着大家手摸手实现一个弹窗组件。…

为 CefSharp 应用内置 C++ 运行环境并启用 AnyCPU 支持

一个 CefSharp 应用程序要想正确运行&#xff0c;有两个必要条件&#xff1a;.NET Framework 4.5.2VC 2015在部署 CefSharp 应用时经常会遇到因为没有 VC 2015 而无法运行的问题&#xff1a;通过事件查看器&#xff0c;可以观察到一个类型为&#xff1a;System.IO.FileNotFound…

java file rename 失败_java重命名文件造成文件不可读写

我想使用java代码对nginx日志文件进行拆分&#xff0c;但是我发现代码执行之后&#xff0c;拆分出来的日志文件没有读写权限&#xff0c;查看文件属性&#xff0c;显示的很诡异&#xff1a;点击高级按钮&#xff0c;显示你没有权限查看或者编辑这个对象的权限设置&#xff1a;反…

java opencsv_用opencsv文件读写CSV文件

首先明白csv文件长啥样儿&#xff1a;用excel打开就变成表格了&#xff0c;看不到细节推荐用其它简单粗暴一点儿的编辑器&#xff0c;比如Notepad&#xff0c;csv文件内容如下&#xff1a;csv文件默认用逗号分隔各列。有了基础的了解就进入主题&#xff0c;用Opencsv读写csv文件…

Beetlex之tcp/tls服务压测工具

在编写tcp服务的时候经常需要对服务的基础性能进行一个压力测试&#xff0c;虽然网上这些工具有很多&#xff0c;但具备使用方便和高强度的测试工具则不多。为了方便这方面的高强度压测所以在beetlex的基础扩展这样一个工具。安装可以访问https://github.com/beetlex-io/TCPBen…

GraphQL:DataLoader的神奇

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述&#xff0c;使得客户端能够准确地获得它需要的数据&#xff0c;而且没有任何冗余&#xff0c;也让 API 更容易地随着时间推移而演进&#xff0c…

【Azure Show】|第九期 “我的计算机入门之路” 嘉宾秦婷婷汪宇杰文轩

欢迎来到Azure Show!Azure Show欢迎来到Azure Show 第九期&#xff01;继上期【搭上AI快车】为大家带来数位微软技术专家于各自IT技术领域的经验分享&#xff0c;有2400多人在线上通过b站看了这个特辑的直播&#xff0c;非常非常感恩&#xff01;本期继续和广州图书馆合作&…

调试实战 | 通过转储文件分析程序无响应之使用 windbg + IDA 逆向篇

缘起 最近&#xff0c;接连在项目中遇到了两个界面无响应的问题。都只发生在客户特定机器上&#xff0c;不方便直接调试&#xff0c;只能抓取 dump 进行事后分析了。抓取 dump 远程连上可以重现问题的机器&#xff0c;使用 process explorer 初步观察卡死的进程&#xff0c;发现…

跟我一起学Redis之高可用从主从复制开始

前言现在遇到高并发场景时&#xff0c;缓存技术应该算是性能优化的第一步&#xff0c;缓解数据库压力的同时还能提高访问效率&#xff0c;而Redis应该是绝大多数应用场景的首选。但是尽快Redis性能再优秀&#xff0c;在当今高并发场景下&#xff0c;一台服务器负责读写&#xf…

【.Net core】EFCore——Code First生成数据库与表

Code First——领域设计模式中非常有用。使用 Code First 模式&#xff0c;专注于领域设计&#xff0c;创建领域类&#xff0c;然后生成数据库。1.创建数据模型类一般就是数据库里面有哪些表&#xff0c;就创建哪些模型&#xff0c; POCO 类就够了。public partial class SmsPu…

龙芯.NET正式发布 开源共享与开发者共成长

2020年12月19日&#xff0c;2020中国. NET开发者大会于苏州盛大开幕。本次大会以“开源、共享、创新”为主题&#xff0c;以线下城市苏州为中心&#xff0c;覆盖北京、上海、深圳、广州、长沙、成都、厦门、胶东等地区&#xff0c;是中国 .NET 开发者的大聚会&#xff0c;线上线…