ASP.NET Core 2.2 下插件化開發的改進

筆者在 Asp.Net MVC 插件化開發簡化方案 研究了基於 .NET Framework 的 ASP.NET 插件化開發以後,又在 ASP.NET Core 2.0 下進行插件化開發 中研究了基於 ASP.NET Core 2.0 的插件化開發,以及在 ASP.NET Core 2.0 中基於 Razor Page 的插件化開發。不過最近在基於 .NET Core 2.1 的插件化開發時遇到個新問題:git

ASP.NET Core 2.1 能夠將視圖編譯在動態庫中,生成一個 proj.views.dll 這樣的動態庫,發佈時就不須要再發布 Views 目錄了。然而使用上述插件化方法,即便 .views.dll 正確的拷貝到目標目錄,甚至 Shadow Copy 和 Assembly 加載都沒有問題的狀況下,運行時仍然要在 Views 目錄下去查找視圖文件。segmentfault

雖然能夠像 2.0 版本那樣拷貝 Views 目錄達到正常運行的效果,可是既然拷貝全部 .dll 就能解決的問題,誰還願意再去多拷貝一個 Views 呢?mvc

筆者查閱了大量資料以後,總算找到了問題的根源:.views.dll 不能採用默認的加載方式,而必須使用 CompiledRazorAssemblyApplicationPartFactory 來加載。CompiledRazorAssemblyApplicationPartFactory 能夠將 Assebmly 加載成 ApplicationPart,再添加到 ApplicationPartManager 中去。所以,須要在 IMvcBuilder.ConfigureApplicationPartManager() 中來配置處理(參閱:Stack Overflow 上的 ASP.NET Core MVC 2.1 mvc Views in plugin框架

不過插件化框架中,爲了解耦平臺和插件,插件 Assembly 是動態搜索並加載的,並不能直接寫硬代碼。這在以前的博客中也曾提到,須要經過 StartupConfigure()ConfigureServices() 配合,並經過一個 mvcBuilder 成員變量來處理。加載仍然要在 LoadPlugins() 中進行(參閱:ASP.NET Core 2.0 下進行插件化開發),而 ConfigureApplicationPartManager() 也須要搬到 LoadPlugins() 中去:asp.net

private void LoadPlugins(IHostringEnvironment env)
{
    // 這裏是以前進行 Shadow Copy 的代碼
    // ......
    // 接下來須要把 dll 按是否 `.views.dll` 來分別處理

    // 從 Shadow Copy 目錄加載 Assembly 並註冊到 Mvc 中
    var groups = Directory.EnumerateFiles(target, "*.dll")
        .GroupBy(path => path.EndsWith(".views.dll", StringComparison.OrdinalIgnoreCase))
        .ToDictionary(group => group.Key);

    // 非 .views.dll 直接加載到爲 ApplicationPart
    groups[false]
        .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath)
        .ForEach(mvcBuilder.AddApplicationPart);

    // .views.dll 須要經過 CompiledRazorAssemblyApplicationPartFactory 來加載
    mvcBuilder.ConfigureApplicationPartManager(manager =>
    {
        var razorPartFactory = new CompiledRazorAssemblyApplicationPartFactory();
        groups[true]
            .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath)
            .SelectMany(assembly => razorPartFactory.GetApplicationParts(assembly))
            .ForEach(manager.ApplicationParts.Add);
    });    
}

相關代碼在 Gitee 上:aspnet-mvc-plugin-sample/asp.net_core_22ui

相關文章
相關標籤/搜索