如何从 Razor Pages 应用程序中的插件动态加载页面?
Posted
技术标签:
【中文标题】如何从 Razor Pages 应用程序中的插件动态加载页面?【英文标题】:How to dynamically load pages from plugins in Razor Pages application? 【发布时间】:2019-05-26 01:29:03 【问题描述】:我正在尝试使用 Razor Pages 应用程序处理插件。
解决方案包含 3 个项目:一个 Razor 页面应用程序和两个 Razor 类库 (RCL)。应用程序不得静态引用 RCL 项目,它们必须作为插件加载:
内页没有什么特别之处。特色页面只生成简单的 html。索引页面构建了一种菜单。
索引页面模型:
public class IndexModel : PageModel
public IEnumerable<MenuItem> MenuItems get; private set;
public void OnGet()
MenuItems = new List<MenuItem>
new MenuItem Route = "FeatureA", Title = "Feature A" ,
new MenuItem Route = "FeatureB", Title = "Feature B"
;
索引页面:
@page
@model IndexModel
@
ViewData["Title"] = "Home page";
<div class="text-center">
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
@foreach (var item in Model.MenuItems)
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/@item.Route">@item.Title</a>
</li>
</ul>
</div>
</div>
当我运行应用程序时,有菜单项,但它们的href
s 是空的:
<div class="text-center">
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" href="">Feature A</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" href="">Feature B</a>
</li>
</ul>
</div>
</div>
当然,所有程序集(应用程序和功能程序)都在同一个目录中。
菜单适用于以下两种情况:
如果我在 App 项目中引用 RCL 项目,这会扼杀插件的想法; 或者如果我将App.deps.json
与 FeatureLib_A
和 FeatureLib_B
作为依赖项(只需从第一个案例中保存 deps 文件,删除引用,全部重建,复制保存的 deps 文件)。
另外,我尝试在 Startup
类中急切地加载 RCL 程序集。
正在加载程序集,但 Index
页面的行为相同。
有没有办法告诉 ASP 基础结构使用 RCL 程序集而不修改 deps 文件?我错过了什么?
【问题讨论】:
【参考方案1】:我想通了。
基本思想是给ApplicationPartManager
适当的应用程序部分。
需要注意的是:
FeatureLib_A.dll
)必须添加为AssemblyPart
;
“view”程序集(例如FeatureLib_A.Views.dll
)必须添加为CompiledRazorAssemblyPart
。
示例代码:
public class Startup
// ...
public void ConfigureServices(IServiceCollection services)
var assemblyLoader = new DotNetCoreAssemblyLoader(searchPattern: "FeatureLib*.dll");
services.AddMvc()
.ConfigureApplicationPartManager(_ =>
foreach (var assembly in assemblyLoader.Assemblies)
if (assembly.FullName.Contains("Views"))
_.ApplicationParts.Add(new CompiledRazorAssemblyPart(assembly));
else
_.ApplicationParts.Add(new AssemblyPart(assembly));
)
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// ...
DotNetCoreAssemblyLoader
是一个自定义类,它使用给定的搜索模式查找程序集文件,并通过AssemblyLoadContext.Default.LoadFromAssemblyPath
加载程序集。
【讨论】:
我试图这样做,我得到“ileNotFoundException:无法加载文件或程序集'Cool.Plugin,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null'。系统找不到指定文件。”【参考方案2】:public class Startup
public Startup( IHostingEnvironment hostingEnvironment)
_hostingEnvironment = hostingEnvironment;
private readonly IHostingEnvironment _hostingEnvironment;
public void ConfigureServices(IServiceCollection services)
...
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.ConfigureApplicationPartManager(ConfigureApplicationParts); ;
private void ConfigureApplicationParts(ApplicationPartManager apm)
string rootPath = _hostingEnvironment.ContentRootPath;
var pluginsPath = Path.Combine(rootPath, "Plugins");
var assemblyFiles = Directory.GetFiles(pluginsPath, "Plugin*.dll", SearchOption.AllDirectories);
foreach (var assemblyFile in assemblyFiles)
try
var assembly = Assembly.LoadFrom(assemblyFile);
if (assemblyFile.EndsWith(".Views.dll"))
apm.ApplicationParts.Add(new
CompiledRazorAssemblyPart(assembly));
else
apm.ApplicationParts.Add(new AssemblyPart(assembly));
catch (Exception e)
【讨论】:
以上是关于如何从 Razor Pages 应用程序中的插件动态加载页面?的主要内容,如果未能解决你的问题,请参考以下文章
结合 Razor Pages 和 ApiControllers 的应用程序中的 Asp.net 核心异常处理
如何使用 .NET Core 2 中的 Razor Pages 更改起始页?
如何正确重定向到 ASP.NET Core Razor Pages 中的同一页面?