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

相关文章
相关标签/搜索