插件模式歷史悠久,各類中大型軟件基本上都會實現插件機制,以此支持功能擴展,從開發部署層面,插件機制也可實現功能解耦,對於並行開發、項目部署、功能定製等都有比較大的優點。git
在.NET Core下,通常咱們基於.NET Core擴展庫進行開發,一般使用依賴注入、配置、設置(Options)等機制,若是將插件模式與依賴注入、配置、設置進行結合,將能夠提供很是靈活的擴展機制。基於此,咱們實現了一個開源的插件框架,本文將進行簡單的介紹。github
示例項目可參考:Xfrogcn.PluginFactory.Example Gitee地址 Github地址json
在主程序項目中添加Xfrogcn.PluginFactory包c#
```dotnet dotnet add package Xfrogcn.PluginFactory ```
在插件項目中添加Xfrogcn.PluginFactory.Abstractions包api
```dotnet dotnet add package Xfrogcn.PluginFactory.Abstractions ```
可經過如下兩種方式來啓用插件庫,一是經過在Host層級的Use機制以及在依賴注入IServiceCollection層級的Add機制,如下分別說明:app
```c# var builder = Host.CreateDefaultBuilder(args); builder.UsePluginFactory(); ```
UsePluginFactory具備多個重載版本,詳細請查看API文檔
默認配置下,將使用程序運行目錄下的Plugins目錄做爲插件程序集目錄, 使用宿主配置文件做爲插件配置文件(一般爲appsettings.json)
你也能夠經過使用帶有 Assembly 或 IEnumerable<Assembly> 參數的版本直接傳入插件所在的程序集框架
```c# var builder = Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.AddPluginFactory(); }); ```
AddPluginFactory具備多個重載版本,詳細請查看API文檔
默認配置下,將使用程序運行目錄下的Plugins目錄做爲插件程序集目錄ide
注意: AddPluginFactory方法不會使用默認的配置文件做爲插件配置,你須要顯式地傳入IConfiguration, 若是是在 ASP.NET Core 環境中,你能夠在Startup類中直接獲取到測試
插件是實現了IPlugin接口的類,在插件庫中也提供了PluginBase基類,通常今後類繼承便可。標準插件具備啓動和中止方法,經過IPluginFactory進行控制。ui
要編寫插件,通常遵循如下步驟:
建立插件項目(.NET Core 類庫),如TestPluginA
添加Xfrogcn.PluginFactory.Abstractions包
```nuget dotnet add package Xfrogcn.PluginFactory.Abstractions ```
建立插件類,如Plugin,從PluginBase繼承
```c# public class Plugin : PluginBase { public override Task StartAsync(IPluginContext context) { Console.WriteLine("插件A已啓動"); return base.StartAsync(context); } public override Task StopAsync(IPluginContext context) { Console.WriteLine("插件A已中止"); return base.StopAsync(context); } } ```
啓動或中止方法中可經過context中的ServiceProvider獲取注入服務
經過PluginAttribute特性設置插件的元數據
```c# [Plugin(Alias = "PluginA", Description = "測試插件")] public class Plugin : PluginBase { } ```
插件元數據以及插件載入的插件列表信息能夠經過IPluginLoader.PluginList獲取
IPluginFactory自己實現了.NET Core擴展庫的IHostedService機制,故若是你是在宿主環境下使用,如(ASP.NET Core),插件的啓動及中止將自動跟隨宿主進行
若是未使用宿主,可經過獲取IPluginFactory實例調用相應方法來完成
```c# // 手動啓動 var pluginFactory = provider.GetRequiredService<IPluginFactory>(); await pluginFactory.StartAsync(default); await pluginFactory.StopAsync(default); ```
在不少場景,咱們須要在插件中控制宿主的依賴注入,如注入新的服務等,這時候咱們可經過實現支持初始化的插件(ISupportInitPlugin)來實現,該接口的Init方法將在依賴注入構建以前調用,經過方法參數IPluginInitContext中的ServiceCollection能夠控制宿主注入容器。
```c# [Plugin(Alias = "PluginA", Description = "測試插件")] public class Plugin : PluginBase, ISupportInitPlugin { public void Init(IPluginInitContext context) { // 注入服務 //context.ServiceCollection.TryAddScoped<ICustomerService>(); } } ```
插件支持 .NET Core 擴展庫中的Options及Configuration機制,你只須要從SupportConfigPluginBase<TOptions>類繼承實現插件便可,其中TOptions泛型爲插件的配置類型。插件配置自動從宿主配置或啓用插件工廠時傳入的配置中獲取,插件配置位於配置下的Plugins節點,該節點下以插件類名稱或插件別名(經過PluginAttribute特性指定)做爲鍵名,此鍵之下爲插件的配置,如如下配置文件:
```appsettings.json { "Plugins": { "PluginA": { "TestConfig": "Hello World" }, } } ```
擴展PluginA實現配置:
定義配置類,如PluginOptions
```c# public class PluginOptions { public string TestConfig { get; set; } } ```
實現插件
```c# [Plugin(Alias = "PluginA", Description = "測試插件")] public class Plugin : SupportConfigPluginBase<PluginOptions>, ISupportInitPlugin { public Plugin(IOptionsMonitor<PluginOptions> options) : base(options) { } public void Init(IPluginInitContext context) { // 注入服務 //context.ServiceCollection.TryAddScoped<ICustomerService>(); Console.WriteLine($"Init 插件配置:{Options.TestConfig}"); } public override Task StartAsync(IPluginContext context) { Console.WriteLine("插件A已啓動"); Console.WriteLine($"StartAsync 插件配置:{Options.TestConfig}"); return base.StartAsync(context); } public override Task StopAsync(IPluginContext context) { Console.WriteLine("插件A已中止"); return base.StopAsync(context); } ```
注意:在插件初始化方法中也可以使用注入的配置
跨插件配置
有些配置可能須要在多個插件中共享,此時你可經過Plugins下的_Share節點進行配置,此節點下配置將會被合併到插件配置中,可經過PluginOptions進行訪問。
```appsettings.json { "Plugins": { "PluginA": { }, "_Share": { "TestConfig": "Hello World" } } } ```
要讓 ASP.NET Core 獲取獲得插件中的控制器,你只須要在插件的初始化方法Init中,向MVC注入插件程序集:
```c# context.ServiceCollection.AddMvcCore() .AddApplicationPart(typeof(Plugin).Assembly); ```