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のプラグイン化開発で新たな問題が発生しました.
ASP.NET Core 2.1は、ビューをダイナミックライブラリにコンパイルし、proj.views.dllのようなダイナミックライブラリを生成することができ、パブリッシュ時にViewsディレクトリをパブリッシュする必要はありません.しかし、上記のプラグイン化方法を使用すると、.views.dllがターゲットディレクトリに正しくコピーされていても、Shadow CopyおよびAssemblyロードに問題がない場合でも、実行時にViewsディレクトリの下でビューファイルを検索する必要があります.
2.0バージョンのようにViewsディレクトリをコピーして正常に動作する効果はありますが、.dllすべてをコピーすれば解決できる問題である以上、誰がもう1つのViewsをコピーしたいですか?
筆者は大量の資料を調べた後、やっと問題の根源を見つけた:.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()に移動する必要があります.
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_22