.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,一经查实,立即删除!

相关文章

java获取机器号_(转)JAVA获得机器码的实现

http://yangshangchuan.iteye.com/blog/2012401首先,定义了一个统一的接口,以支持不同操作系统不同实现的透明切换:Java代码 收藏代码/***生成机器码的接口,不同平台有不同实现* author 杨尚川*/public interface SequenceServic…

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

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

Java pdf文件传输_java中pdf文件的管理(pdf文件转png文件,base64传输文件以及删除)...

org.apache.pdfboxpdfbox2.0.12影像文件转为base64编码使用java自带的BASE64Encoder类代码部分:前端上传文件的保存:RequestMapping("upLoadImgs")ResponseBodypublic String upLoadAgreementsImg(HttpServletResponse response, HttpServletR…

【对比学习】koa.js、Gin与asp.net core——中间件

web框架中间件对比编程语言都有所不同,各个语言解决同一类问题而设计的框架,确有共通之处,毕竟是解决同一类问题,面临的挑战大致相同,比如身份验证,api授权等等,鄙人对node.js,golan…

java 传送解析8583报文_java发送ISO8583报文接口案例

【实例简介】java发送ISO8583报文实现平安银行支付接口【实例截图】【核心代码】pingAnBank└── pingAnBank├── build.xml├── client│ ├── ClientBean.java│ ├── UDPClient.java│ └── UdpClientSocket.java├── com│ └── solab│ └── i…

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字符串切分_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 …

ldap java 密码_用java进行LDAP用户登陆(用户认证)及修改密码

一、用户认证public String execute(){Hashtable env new Hashtable();String LDAP_URL "ldap://8.8.8.8:389"; // LDAP访问地址env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");env.put(Context.PROVIDER_URL, LDAP_URL)…

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

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

java 3des 32位密钥_3des,java_java 中32位秘钥长度的 3des加密方法?,3des,java - phpStudy...

java 中32位秘钥长度的 3des加密方法&#xff1f;java中 3des加密 默认是24位秘钥的现在需求是 32位秘钥加密尝试很多种方法 解决 结果都不正确// 密钥private final static String secretKey "11111111111111111111111111111111";// 向量// private final static S…

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

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

java怎么判断数据类型_数据类型判断

[java]代码库import java.util.*; public class Main{public static void main(String[] args) {Scanner scan = new Scanner(System.in); String s = scan.nextLine(); String []str = s.split(" "); int i, j; for(i = 0; i < str.length; i++) {if(i != 0) Sys…

.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;下面本文会带着大家手摸手实现一个弹窗组件。…

拆分路径 java_JAVA 类文件中的路径如何拆分和替换

我做Swing的时候文件要放绝对路径&#xff0c;相对路径出不来&#xff01;所以我用如果我的类放在D:\aaa\Class里Thread.currentThread().getContextClassLoader().getResource("");MenuTest.class.getClas...我做Swing的时候文件要放绝对路径&#xff0c;相对路径出…

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

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