Как динамически загружать страницы из плагинов в приложении Razor Pages? - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь разобраться с плагинами с помощью приложения Razor Pages.

Решение состоит из 3 проектов: одно приложение Razor Pages и две библиотеки классов Razor (RCL).Приложение не должно ссылаться на проекты RCL статически, они должны быть загружены как плагины:

enter image description here

Внутри страниц нет ничего особенного.Функциональные страницы просто создают простой 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 пустые:

<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>

Конечно, все сборки (приложения и компоненты) находятся в одном каталоге.

Меню работает в двух следующих случаях:

  • либо если я ссылаюсь на проекты RCL в проекте App, который убивает идею плагинов;
  • , либо если я ставлю App.deps.json с FeatureLib_A и FeatureLib_B как зависимости (просто сохраните файл depsв первом случае удалите ссылки, перестройте все, скопируйте сохраненный файл deps).

Также я пытался загружать сборки RCL в классе Startup.Сборки загружаются, но страница Index ведет себя так же.

Есть ли способ указать инфраструктуре ASP использовать сборки RCL без изменения файла deps?Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 24 мая 2019
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) { }
        }
    }
}
0 голосов
/ 28 декабря 2018

Я понял это.

Основная идея - дать ApplicationPartManager соответствующих частей приложения.
Важно отметить, что:

  • "код"сборки (например, FeatureLib_A.dll) должны быть добавлены как AssemblyPart;
  • сборки "вида" (например, 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.

...