OrchardCore 如何動態加載模塊?

前言

今天,我們再次討論下OrchardCore,通過初期調研,我們項目採用OrchardCore底層設施支持模塊化,同時根據業務場景,額外還需支持二次開發,於是有了本文,若有不同解決方案,歡迎留言探討

 

​若對OrchardCore有所瞭解的童鞋應該知道,OrchardCore本身定位於CMS系統,同時整個架構並非前後分離,採用MVC模式開發,基於此,由於內置需要預編譯視圖以及考慮其他等等原因,不支持動態加載模塊,本文給出我所想到的動態加載模塊方案

OrchardCore基本使用示例

OrchardCore採用包管理各個模塊,所以有自建NuGet,我們提前配置好OrchardCore程序包源

 

項目採用前後分離,所以我們創建WebAPi應用程序,爲支持模塊化開發,如上圖下載模塊開發應用程序包,緊着在Startup文件中,添加OrchardCore服務以及使用其中間件,如下圖

 至此一個基本的模塊化項目就創建完畢,接下來我們創建模塊,官方提供模塊包模板引擎

通過對應命令將模板引擎下載至本地

dotnet new -i OrchardCore.ProjectTemplates::1.0.0-rc2-16113 --nuget-source https://nuget.cloudsmith.io/orchardcore/preview/v3/index.json

 然後我們在項目解決方案下,繼續通過CLI將下載至本地模板引擎來創建模塊項目,並引入到項目解決方案中

dotnet new ocmodulecms -n Test

由於我們用不到視圖,所以將視圖文件夾以及對應默認安裝包刪除,只需保留模塊包【OrchardCore.Module.Targets】就好,同時也一併將項目文件中支持MVC配置給刪除,否則會生成視圖程序集,猜測應該會引起模塊加載依賴需額外加載視圖dll

我們將模塊默認創建控制器修改爲訪問接口形式,方便接下來測試驗證

 那麼接下來我們應該如何將開發好的模塊進行加載呢?

OrchardCore動態加載模塊(前後分離)

瞭解OrchardCore基本原理的我們應該知道,默認情況下,主項目添加模塊引用時,會通過MSBuild在對應模塊程序集中,添加模塊標識,如下:

 

​如上圖所示,一個是模塊標識,一個是對應文件路徑標識,當啓動主項目時,會找到對應程序集模塊標識,並註冊服務以及其他操作,如此看來,我們只需深入瞭解源碼中是否存在存儲對應模塊信息的接口呢?

 

查看底層模塊設施源碼,得知對外暴露其接口即IModuleNamesProvider,我們將生成模塊dll放在主項目程序啓動modules目錄下,接下來我們實現該接口,如下:

public class DynamicModuleNamesProvider : IModuleNamesProvider
{
    private readonly List<string> _moduleNames = new List<string>();

    public DynamicModuleNamesProvider()
    {
        var baseDirectory = AppContext.BaseDirectory;

        var location = Path.Combine(baseDirectory, "modules");

        if (!Directory.Exists(location))
        {
            return;
        }

        foreach (var file in Directory.EnumerateFiles(location))
        {
            var assemblyPath = Path.Combine(location, file);

            var assembly = Assembly.LoadFrom(assemblyPath);

            _moduleNames.AddRange(assembly.GetCustomAttributes<ModuleMarkerAttribute>().Select(m => m.Name));
        }
    }

    public IEnumerable<string> GetModuleNames()
    {
        return _moduleNames;
    }
}

將其以單例形式注入,如下

services.AddSingleton<IModuleNamesProvider, DynamicModuleNamesProvider>();

我們啓動主項目驗證確認,模塊已然進行加載,如下:

但是訪問控制器接口卻顯示404

 

 並未繼續深入查看源碼,至少可知,通過動態加載內置僅僅只註冊了相關服務,猜測是和移除對應視圖包有關導致並未激活控制器、視圖等等

OrchardCore動態加載模塊激活控制器

由於控制器、視圖、TagHelper等等相關FeatureProvider並未激活,所以我們藉助AssemblyPart來實現,將其作爲應用程序的一部分,通過掃描模塊,將對應控制器等激活,如下:

var builders = services.AddControllers();

builders.ConfigureApplicationPartManager(apm =>
{
    var baseDirectory = AppContext.BaseDirectory;

    var location = Path.Combine(baseDirectory, "modules");

    if (!Directory.Exists(location))
    {
        return;
    }

    foreach (var file in Directory.EnumerateFiles(location))
    {
        var assemblyPath = Path.Combine(location, file);

        var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);

        var assemblyPart = new AssemblyPart(assembly);

        apm.ApplicationParts.Add(assemblyPart);
    }
});

總結

雖然官方並未提供動態加載模塊示例,但我們依然可以借用其對外暴露接口來實現,理論上若是採用MVC模式,應該也可以進行動態加載!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章