.NET Core 中插件式开发实现
在 .NET Framework 中,通过AppDomain实现动态加载和卸载程序集的效果;但是.NET Core 仅支持单个默认应用域,那么在.NET Core中如何实现【插件式】开发呢?
一、.NET Core 中 AssemblyLoadContext的使用
1、AssemblyLoadContext简介:
每个 .NET Core 应用程序均隐式使用 AssemblyLoadContext。它是运行时的提供程序,用于定位和加载依赖项。只要加载了依赖项,就会调用 AssemblyLoadContext 实例来定位该依赖项。
-
它提供定位、加载和缓存托管程序集和其他依赖项的服务。
-
为了支持动态代码加载和卸载,它创建了一个独立上下文,用于在其自己的 AssemblyLoadContext 实例中加载代码及其依赖项。
2、AssemblyLoadContext和AppDomain卸载差异:
使用 AssemblyLoadContext
和使用 AppDomain 进行卸载之间存在一个值得注意的差异。对于 Appdomain,卸载为强制执行。
卸载时,会中止目标 AppDomain 中运行的所有线程,会销毁目标 AppDomain 中创建的托管 COM 对象,等等。对于 AssemblyLoadContext
,卸载是“协作式的”。
调用 AssemblyLoadContext.Unload 方法只是为了启动卸载。以下目标达成后,卸载完成:
1、没有线程将程序集中的方法加载到其调用堆栈上的 AssemblyLoadContext
中。
2、程序集中的任何类型都不会加载到 AssemblyLoadContext
,这些类型的实例本身由以下引用:
-
-
AssemblyLoadContext
外部的引用,弱引用(WeakReference 或 WeakReference)除外。 -
AssemblyLoadContext
内部和外部的强垃圾回收器 (GC) 句柄(GCHandleType.Normal 或 GCHandleType.Pinned)。
-
二、.NET Core 插件式方式实现
1、创建可卸载的上下文PluginAssemblyLoadContext
class PluginAssemblyLoadContext : AssemblyLoadContext
{private AssemblyDependencyResolver _resolver;/// <summary>/// 构造函数/// isCollectible: true 重点,允许Unload/// </summary>/// <param name=pluginPath></param>public PluginAssemblyLoadContext(string pluginPath) : base(isCollectible: true){_resolver = new AssemblyDependencyResolver(pluginPath);}protected override Assembly Load(AssemblyName assemblyName){string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);if (assemblyPath != null){return LoadFromAssemblyPath(assemblyPath);}return null;}protected override IntPtr LoadUnmanagedDll(string unmanagedDllName){string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);if (libraryPath != null){return LoadUnmanagedDllFromPath(libraryPath);}return IntPtr.Zero;}
}
2、创建插件接口及实现
整体项目结构为:
a)添加项目PluginInterface,插件接口:
public interface IPlugin
{string Name { get; }string Description { get; }string Execute(object inPars);
}
b)添加HelloPlugin项目,实现不引用外部dll插件
public class HelloPlugin : PluginInterface.IPlugin
{public string Name => "HelloPlugin";public string Description { get => "Displays hello message."; }public string Execute(object inPars){return ("Hello !!!" + inPars?.ToString()); } }
c)添加JsonPlugin项目,实现引用三方dll插件
public class JsonPlugin : PluginInterface.IPlugin
{public string Name => "JsonPlugin";public string Description => "Outputs JSON value.";private struct Info{public string JsonVersion;public string JsonLocation;public string Machine;public DateTime Date;}public string Execute(object inPars){Assembly jsonAssembly = typeof(JsonConvert).Assembly;Info info = new Info(){JsonVersion = jsonAssembly.FullName,JsonLocation = jsonAssembly.Location,Machine = Environment.MachineName,Date = DateTime.Now};return JsonConvert.SerializeObject(info, Formatting.Indented);}
}
d)添加PluginsApp项目,实现调用插件方法:
修改窗体界面布局:
添加执行方法
/// <summary>
/// 将此方法标记为noinline很重要,否则JIT可能会决定将其内联到Main方法中。
/// 这可能会阻止成功卸载插件,因为某些实例的生存期可能会延长到预期卸载插件的时间点之外。
/// </summary>
/// <param name="assemblyPath"></param>
/// <param name="inPars"></param>
/// <param name="alcWeakRef"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.NoInlining)]
static string ExecuteAndUnload(string assemblyPath, object inPars, out WeakReference alcWeakRef)
{string resultString = string.Empty;// 创建 PluginLoadContext对象var alc = new PluginAssemblyLoadContext(assemblyPath);//创建一个对AssemblyLoadContext的弱引用,允许我们检测卸载何时完成alcWeakRef = new WeakReference(alc);// 加载程序到上下文// 注意:路径必须为绝对路径.Assembly assembly = alc.LoadFromAssemblyPath(assemblyPath);//创建插件对象并调用foreach (Type type in assembly.GetTypes()){if (typeof(IPlugin).IsAssignableFrom(type)){IPlugin result = Activator.CreateInstance(type) as IPlugin;if (result != null){resultString = result.Execute(inPars);break;}}}//卸载程序集上下文alc.Unload();return resultString;
}
三、效果验证
1、非引用外部dll的插件执行:执行后对应dll成功卸载,程序集数量未增加。
2、引用外部包的插件:执行后对应dll未卸载,程序集数量增加。
通过监视查看对象状态:该上下文在卸载中。暂未找到原因卸载失败(疑问?)
四、总结
虽然微软文档说.NET Core中使用AssemblyLoadContext来实现程序集的加载及卸载实现,但通过验证在加载引用外部dll后,加载后不能正常卸载。或者使用方式还不正确。
源码地址:https://github.com/cwsheng/PluginsApp
相关文章:

.NET Core 中插件式开发实现
在 .NET Framework 中,通过AppDomain实现动态加载和卸载程序集的效果;但是.NET Core 仅支持单个默认应用域,那么在.NET Core中如何实现【插件式】开发呢? 一、.NET Core 中 AssemblyLoadContext的使用 1、AssemblyLoadContext简…...

并查集模版以及两道例题
💯 博客内容:并查集 😀 作 者:陈大大陈 🚀 个人简介:一个正在努力学技术的准C后端工程师,专注基础和实战分享 ,欢迎私信! 💖 欢迎大家:这里是C…...

英飞凌TLF35584规格书中文
官网: 英飞凌TLF35584QVVS2 TLF35584_SPI: 1 Overview2 Block Diagram3 Pin Configuration3.1 Pin Assignment - PG-VQFN-48 4 General Product Characteristics4.1 Absolute Maximum Ratings 绝对最大额定值4.2 Functional Range4.3 Thermal Resistance…...

【教3妹学编程-算法题】最大单词长度乘积
3妹:哇,今天好冷啊, 不想上班。 2哥:今天气温比昨天低8度,3妹要空厚一点啊。 3妹 : 嗯, 赶紧把我的羽绒服找出来穿上! 2哥:哈哈,那倒还不至于, 不过气温骤降&…...

遇到python程序是通过sh文件启动的,如何调试
说明 下载的源码总会遇到这样启动的: 并且发现shell文件内容很多,比较复杂,比如: 解决方案 这时候想要调试,可以通过端口连接的方式调试,具体方法如下: 在vscode调试按钮中添加远程附加调试…...

应用系统集成-Spring Integration
应用系统集成-Spring Integration 图1 EIP 消息系统模式全景图。 Spring Integration 是系统集成的一个实现框架,提供了对EIP核心概念:Endpoint、Message、Channel、Router、Translator的抽象及相关框架实现,使得基于Spring Integration进行…...

亚马逊与TEMU平台欧代英代如何注册?注册欧代/英代流程及注意事项
亚马逊与TEMU平台欧代英代如何注册?注册欧代/英代流程及注意事项 亚马逊平台的商家的产品,由于受到欧盟商品安全新法规市场监管法规欧盟要求所有标有CE标志的商品,都要拥有欧盟境内的欧代作为商品合规的联系方式(也称为负责人)。由于英国脱离…...

【嵌入式开发工具】STM32+Keil实现软件工程搭建与开发调试
本篇文章介绍了使用Keil来对STM32F103C8芯片进行初始工程搭建,以及开发与工程调试的完整过程,帮助读者能够在实战中体会到Keil这个开发环境的使用方法,了解一个嵌入式工程从无到有的过程,并且具备快速搭建一个全新芯片对应最小软件…...

python 去除图像中的框
最近在做图像标注,会出现以下的图片,需要去除其中的边框。 1.思路 人工标注画框的范围P,并使用标注工具在画框上画一个点A。获取点A的坐标和颜色。在范围P内,将与点A颜色相似的每一个点x的颜色,替换为点x上下&#…...

企业邀约媒体的方式方法?-(快速精准)
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 快速而精确地邀约媒体通常需要有计划和策略性的方法。以下是一些方法,可以帮助企业有效地邀请媒体: 1. 媒体列表构建:首先,建立一个精心筛…...

旅游业为什么要选择VR全景,VR全景在景区旅游上有哪些应用
引言: VR全景技术的引入为旅游业带来了一场变革。这项先进技术不仅提供了前所未有的互动体验,还为景区旅游文化注入了新的生机。 一.VR全景技术:革新旅游体验 1.什么是VR全景技术? VR全景技术是一种虚拟现实技术&am…...

搭建第一个区块链网络与一键部署WeBASE步骤
官网 搭建第一个区块链网络 — FISCO BCOS v2 v2.9.0 文档 (fisco-bcos-documentation.readthedocs.io) 一键部署 — WeBASE v1.5.5 文档 (webasedoc.readthedocs.io) 步骤 默认如MySQL、Python、java等依赖已经引入 1.创建操作目录, 下载安装脚本 创建操作目录 cd ~ &a…...

MTK联发科、高通、紫光展锐手机SOC平台型号汇总(含详细参数)
MediaTek联发科手机平台汇总: Qualcomm高通SOC平台汇总: 紫光展锐SOC平台汇总: 新移科技已成功研发手机SOC平台: 联发科平台: MTK6739、MTK6761、MTK6762、MTK6765、MTK8788、MTK6853、MTK6873、MTK6833、MTK6877、…...

【ARM AMBA AXI 入门 12 -- AXI协议中的 WLAST 与 RLAST】
文章目录 AXI协议中的 WLAST 与 RLAST AXI协议中的 WLAST 与 RLAST AMBA AXI协议是由ARM公司定义的一种高性能,高频率的总线协议。总线协议中的 WLAST 信号是一个重要的信号,它在 AXI 协议中用来标识一个突发(Burst)传输的最后一…...
11.6 知识总结(筛选器方法、操作标签、事件)
一、 筛选器方法 document.getElementById()------>标签对象------------>直接就是标签 $(document.getElementById()) -------> jQuery对象-------->可以使用jQuery提供的方法 jQuery(document.getElementById()) -------> jQuery对象-------->可以使用jQue…...

Devchat插件:AI智能编程助手,让你告别脏活累活。
文章目录 前言注册登录DevChat的安装和配置DevChat插件安装DevChat插件配置 DevChat的简单使用后记 前言 随着人工智能技术的不断发展和普及,它正在深刻影响着各行各业,并逐渐成为改变世界的重要力量。在软件开发领域,人工智能技术也给开发者…...

0-1矩阵列互斥问题——回溯法 Python实现
三、 0-1 矩阵的列集互斥问题。给定一个 m n m \times n mn 的 0-1 矩阵 A \mathrm{A} A 。定义列互斥为: 对于矩阵 A A A 中的任意两列 i i i 和 j j j, 如果在对应的每一行上, i i i 和 j j j 不存在同时为 1 的情况, 则称列 i \mathrm{i} i 和 j \mathrm{j} j 互斥…...

wandb 安装本地部署使用教程
1、官网注册 wandb.ai是一个为机器学习开发者提供的开发工具平台,可以帮助用户跟踪实验,管理和版本数据,以及与团队协作,从而更专注于构建最佳模型。 wandb官网: https://wandb.ai 首先我们打开官网注册号自己的账号并…...

飞桨平台搭建PP-YOLOE模型
一、创建项目 此博客仅是运行PP-YOLOE源码,这里以变压器渗漏数据集为例COCO数据集太大了,跑不动,V100训练预估计得7天左右,即便是A100也得4天半,变压器渗漏油数据集跑一个小时左右,还可以接受,…...
Js重点内容
一,什么是js javascript是运行在客户端(浏览器,可预览)的编程语言 二,主要的功能 用来给静态页(html网页)增加一些动态功能(比如轮播图、tab切换) 三,应用…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...