Natasha 4.0 探索之路系列(二) 「域」与插件
域与ALC
在 Natasha 发布之后有不少小伙伴跑过来问域相关的问题,能不能兼容 AppDomain、如何使用 AppDomain、为什么 CoreAPI 阉割了 AppDomain
等一系列的问题。
今天答复一下:
首先
AppDomain
作为程序集隔离容器的存在,是风靡了 .NET Framework 的各大版本,被誉为是轻量级进程,由 AppDomain 发展的特性和操作也很多。而 Natasha 采用的是AssemblyLoadContext
简称 "ALC";ALC 是 .NET Core 版本后出现的操作类,这个类在 .NET Core 及以后的版本中,只要加载依赖项,就会调用它。有趣的是,你在调试代码过程中如果去观察它,可以看到它缓存程序集的数量在增加。因为还没运行到的程序集可以先不加载,检测代码AssemblyLoadContext.Default.Assemblies.Count()
;其次它本不是域,或者不能称为域。它和域的区别是,FW 支持多域,而 CORE 仅支持单域,CORE 就一个默认域。ALC 的名字翻译过来是,程序集加载上下文,看英文名字也是和域区分开了;
最后一点区别是域的卸载是强制的,ALC 的卸载是“协商”的,相比域而言,ALC 中的程序集所包含的元数据被保持引用,就不能被卸载,比如你反射出来的类或者方法或者其他什么的放到了一个主域的字典中,那么字典不毁,这个 ALC 就没办法卸载,尽管 ALC 有 Unload 方法,卸载还是要看元数据是否被保持引用;
Natasha 设计初衷是使用隔离性较强的字眼,用域的概念来减少 .NET Core 带来的新的理解成本,另外之前有打算兼容 AppDomain
的想法。
这个想法的优先级不高:
是 .NET Core 是在 3.0 时出现比较明显的分水岭,包括依赖解析,上下文域识别等重要特性的支持;
是 Roslyn 对 FW 的支持不能低于(4.6.1);
是 UT测试需要区分版本来做,很麻烦,插件部分的测试不简单;
是 个人精力原因,还要工作,还要维护其他项目;
这里也希望公司们都能平稳度过升级期,早点迎接更好更实用的"未来技术"。
Natasha 域的使用
插件的开发技巧
这里不得不回顾一下插件开发的知识,它可不是像培训机构讲的编译一个 DLL 然后 Assembly.LoadFrom
就可以的。首先要了解加载插件的两个侧重点,插件依赖打包和插件依赖管理。
插件依赖打包:首先插件生成时,你需要把必要的引用库一起打包,此时需要在工程文件的
PropertyGroup
节点中添加<EnableDynamicLoading>true</EnableDynamicLoading>
让编译程序输出依赖文件,同时不要忘了交付 "xxx.deps.json",这是让宿主程序解析依赖的关键;插件依赖管理:如果你的接口
IPlugin
给到插件开发人员,让他按照这个接口去写功能,那么当他交付插件时,你不能再将他包里的IPlugin
再引进来。否则如下代码将报错,(var plugin = (IPlugin)Activtor.Create(pluginA);
) 类型转换错误,原因是代码中的IPlugin
在主域中使用,而pluginA
是加载到其他域中的,而且在那个域里也存在一个IPlugin
,这个接口类型不同于主域的接口类型,因此在转换时会引发类型转换的错误。解决方法1:让插件开发人员在自己的工程添加设置,自动排除这个主要依赖(官方的推荐做法):
<ItemGroup><ProjectReference Include="..\IPlugin\IPlugin.csproj"><Private>false</Private><ExcludeAssets>runtime</ExcludeAssets></ProjectReference></ItemGroup>
解决方法2:在实现的 ALC 中添加过滤方法排除
IPlugin
以上是基本的插件开发知识,如果你还不了解,可以读一读微软插件开发文档。
https://docs.microsoft.com/zh-cn/dotnet/core/tutorials/creating-app-with-plugin-support
单独使用 NatashaDomain :
引入包
DotNetCore.Natasha.Domain
包。加载插件
NatashaDomain domain = new NatashaDomain("NewPluginDomain");//加载方法: 参数1: 插件位置;参数2: 根据 AssemblyName 排除需要加载的插件名称。//加载插件,如果主域存在相同名字的依赖,则使用版本较高的那版。domain.LoadPluginWithHighDependency("c:/xxx/pluginA.dll", excludeAssembliesFunc: asn => asn.Name.Contains("IPlugin"));//加载插件,如果主域存在相同名字的依赖,则使用版本较低的那版。domain.LoadPluginWithLowDependency("c:/xxx/pluginA.dll", excludeAssembliesFunc: asn => asn.Name.Contains("IPlugin"));//加载插件,如果主域存在相同名字的依赖,则使用主域中的那版。domain.LoadPluginUseDefaultDependency("c:/xxx/pluginA.dll");//加载插件,不判重,全部加载。domain.LoadPluginWithAllDependency("c:/xxx/pluginA.dll", excludeAssembliesFunc: asn => asn.Name.Contains("IPlugin"));//卸载域domain.Dispose();
避坑指南
如果您使用以上 API 将插件加载到同一个域,会出现很多问题:
建议:
写插件时,本身解决好引用管理问题;
如果插件过于庞大,请将插件功能解耦,并加载到不同域中反射给主域执行;
主域要对依赖使用版本检查,请在插件加载代码之前执行一些功能。比如
_ = typeof(Dapper.CommandDefinition);
尽管这句没有用,但它将迫使运行时将 Dapper 的程序集加载到默认上下文的缓存中,这样在你加载插件时,如果遇到 Dapper 依赖,将触发版本检查详见代码。https://github.com/dotnetcore/Natasha/blob/main/samples/PluginSample/PluginSample/Program.cs#L145
结尾
您可以自行查看案例代码。NatashaDomain
是 Natasha 动态编译的父级,Natasha 动态编译中的 NatashaReferenceDomain
继承了此类,因此如果您想使用 Natasha 进行动态构建请使用 NatashaReferenceDomain
。下一篇将讲解 Natasha 的基本编译知识。
Natasha 4.0 探索之路系列(二) 「域」与插件相关推荐
- Natasha 4.0 探索之路系列(三) 基本的动态编译
相关文章 Natasha 4.0 探索之路系列(一) 概况 Natasha 4.0 探索之路系列(二) 「域」与插件 Natasha 的设计 动态编译 Roslyn 为开发者提供了动态编译的接口,允许 ...
- Natasha 4.0 探索之路系列(四) 模板 API
相关文章 Natasha 4.0 探索之路系列(一) 概况 Natasha 4.0 探索之路系列(二) 「域」与插件 Natasha 模板 Natasha 在编译单元的基础上进行了封装整理, 并提供了 ...
- Natasha 4.0 探索之路系列(一) 概况
简介 Natasha 是一个基于 Roslyn 的动态编译类库,它以极简的 API 完成了动态编译的大部分功能,使用它可以在程序运行时编译出新的程序集. Natasha 允许开发人员直接使用 C# 代 ...
- 「域」是什么 ? 小学就接触的知识,没想到却这么烧脑?
▲ 本书参与当当每满100-40活动, 链接见文末 1. 什么是"域" 伽罗瓦提出一种名为"有限域"(finite field,日语将其称为"有限体& ...
- 【VMware vRealize Suite 2019 部署系列】- 「2」 – 部署 vRealize Operations 8.1
[VMware vRealize Suite 2019 部署系列]- 「2」 – 部署 vRealize Operations 8.1 vRealize Operations 8.x 小旭 10个 ...
- 快手直播电商2.0时代:从「货」到「人」,重构商品交易逻辑
3月26日,快手电商在杭州举办了"2021快手电商引力大会".大会宣布快手电商开启直播电商2.0时代,并发布"商家全周期红利计划",这也是快手电商成立以来首次以 ...
- 电商4.0时代 新的「开端」
随着电子商务行业向4.0时代迈进,供应商.代理商.消费者之间的关系拥有着更多层次的交互与转变,B2C企业更是由垂直走向综合,由商品走向服务. 朴朴超市(福州朴朴电子商务公司),是一家「30分钟即时配送 ...
- 数字图像处理系列(二)---空间域图像增强-点运算
chapter2 空间域图像增强(点增强) 1.图像增强的基本概念 在不考虑图像降质的情况下,通过经验和试探的方法,把图像感兴趣的部分进行选择性突出,而把不在意的部分进行压制,从而得到我们想要的信息. ...
- html 轮播图_JS拖拽专题(二)——「实战」滑动轮播图的那点事儿
欢迎来到我的JS拖拽专题系列文章,更多精彩内容持续更新中,欢迎关注 :) 上一章节我们说到了在js中拖拽的基本原理,即我们在鼠标按下的时候计算出鼠标位置和物理的位置的差值,这个差值在移动的过程中不恒定 ...
最新文章
- 东北大学计算机 大一物理考试题,2020年东北大学822《大学物理》考试大纲及样题...
- 用数据说话——IOPS:RAID1+0 RAID5
- Autofac 解释第一个例子 《第一篇》
- PHP-Zend引擎剖析之Hello World(二)
- 10601 - Cubes(Ploya)
- 2017年第八届蓝桥杯 - 省赛 - C/C++大学A组 - B. 跳蚱蜢
- 点赞!刘强东:无论京东员工遭遇何种不幸,将负责其子女费用到22岁
- 算法应用-百钱买百鸡
- MATLAB读取和写入Excel文件
- linux安装或卸载mysql5,Linux环境下卸载、安装及配置MySQL5.1
- 20145231熊梓宏 《网络对抗》 实验6 信息搜集与漏洞扫描
- tomcat .appcache html5离线缓存,html5 application cache遇到的严重问题
- KNN算法(10折交叉验证)
- tftpd linux,用DHCP,NFS,tftpd搭建PXE无人值守安装linux操作系统
- 免费的文字转语音软件有哪些?三款软件可考虑,助你完成配音
- 怎么定位前后端问题之-图片显示不出来显示空白等
- RFC(请求注解)--各种协议-标准
- 服务器413是什么状态,服务器异常代码413问题
- 动手学深度学习笔记3.1+3.2+3.3
- mysql基本语句大全6_mysql基本sql语句大全(基础用语篇)
热门文章
- 怎么发表博客,还不能显示在自己的博客首页上,这还不如玩单机!
- 在IE11下设置SharePoint Server 2013却遇到“需要 Internet Explorer 才能使用此功能。”的解决办法...
- C++中事件机制的简洁实现
- Comet OJ - Contest #0题解
- 如何查看服务器并发请求连接数
- (10.1)Python学习笔记二
- 2016-2017-2学期《程序设计与数据结构》教学进程
- 二叉查找树转换成有序的双向链表
- 【Android笔记】如何创建列表视图3
- airdrop 是 蓝牙吗_您可以在Windows PC或Android手机上使用AirDrop吗?