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 就能解决的问题,谁还愿意再去多拷贝一个 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

阅读 2k

推荐阅读
边城客栈
用户专栏

全栈技术专栏

3148 人关注
77 篇文章
专栏主页