【问题标题】:How to dynamically load pages from plugins in Razor Pages application?如何从 Razor Pages 应用程序中的插件动态加载页面?
【发布时间】: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>

当我运行应用程序时,有菜单项,但它们的hrefs 是空的:

<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.jsonFeatureLib_AFeatureLib_B 作为依赖项(只需从第一个案例中保存 deps 文件,删除引用,全部重建,复制保存的 deps 文件)。

另外,我尝试在 Startup 类中急切地加载 RCL 程序集。 正在加载程序集,但 Index 页面的行为相同。

有没有办法告诉 ASP 基础结构使用 RCL 程序集而不修改 deps 文件?我错过了什么?

【问题讨论】:

    标签: c# asp.net-core razor-pages


    【解决方案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) { }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-04-05
      • 2022-07-23
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-11
      相关资源
      最近更新 更多