日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Natasha 4.0 探索之路系列(二) 「域」与插件

發布時間:2023/12/4 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 探索之路系列(二) 「域」与插件的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。