ASP .NET Core MVC 2.1 mvc Просмотров в плагине - PullRequest
0 голосов
/ 09 октября 2018

У меня есть проблема, которая мучила меня в течение нескольких дней.

Как я делаю в плагине в ASP .NET Core MVC, чтобы принести мне взгляды с плагином

У меня такая ситуация

решение: EVS

  • Контроллеры
    • ...
  • Просмотры
    • ...
  • Плагины
    • эта папка содержит плагины dll
  • другие папки ...
  • IPlugin.cs
  • Program.cs
  • Startup.cs

файл IPlugin.cs

...
using McMaster.NETCore.Plugins;

namespace EVS
{
    public interface IPlugin
    {
        string Name { get; }
        void Do();
        void BootReg();
        void BootExecute();
        void PluginConfigure(IApplicationBuilder app, IHostingEnvironment env);
        void PluginConfigureServices(IServiceCollection services);
    }

    public class PluginsManager
    {
        public List<PluginLoader> PluginLoaders;

        public Dictionary<string, IPlugin> Plugins;
        public Dictionary<string, Assembly> Views;
        public List<String> dllFileNames;

        public PluginsManager()
        {
            PluginLoaders = new List<PluginLoader>();
            Plugins = new Dictionary<string, IPlugin>();
            dllFileNames = new List<string>();
            string PloginDirectory= Path.Combine(AppContext.BaseDirectory, "Plugins");
            if (Directory.Exists(PloginDirectory))
                dllFileNames.AddRange(Directory.GetFiles(PloginDirectory+"\\", "*.dll"));

            foreach (string dllFile in dllFileNames)
            {
                if (!dllFile.Contains(".Views.dll"))
                {
                    var loader = PluginLoader.CreateFromAssemblyFile(dllFile,sharedTypes: new[] { typeof(IPlugin) });
                    PluginLoaders.Add(loader);               
                }
                else
                {
                    // 

                    //
                }   
            }
            foreach (var loader in PluginLoaders)
            {
                foreach (IPlugin plugin in loader.LoadDefaultAssembly().GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract).Select((x)=> (IPlugin)Activator.CreateInstance(x)))
                    if (!Plugins.ContainsKey(plugin.Name))
                        Plugins.Add(plugin.Name, plugin);
            }
        }
    }
}

файл Program.cs

namespace EVS
{
    public class Program
    {
        public static void Main(string[] args)
        {
            foreach (IPlugin plugin in Global.Static.PluginsManager.Plugins.Select((x) => x.Value))
                plugin.BootReg();           

            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

файл Startup.cs

namespace EVS
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            foreach (IPlugin plugin in Global.Static.PluginsManager.Plugins.Select((x) => x.Value))
            {
                plugin.PluginConfigureServices(services);
            }                
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();
            app.UseCookiePolicy();

            foreach (IPlugin plugin in Global.Static.PluginsManager.Plugins.Select((x) => x.Value))
            {
                plugin.PluginConfigure(app,env);
            }

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Теперь давайте рассмотрим пример плагинов

решение: EVS.TestPlugin

  • Контроллеры
    • TestPluginController.cs
  • Просмотры
    • test.cshtml
  • TestPlugin.cs

файл: TestPlugin.cs

namespace EVS.TestPlugin
{
    internal class TestPlugin : IPlugin
    {
        public string Name
        {
            get
            {
                return "TestPlugin";
            }
        }

        public void BootReg()
        {
            ...
        }

        public void BootExecute()
        {
            ...
        }

        public void Do()
        {

        }


        public void PluginConfigure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseMvc(routes =>
            {
                routes.MapRoute("TestPlugin", "TestPlugin/", new { controller = "TestPlugin", action = "index" });
                routes.MapRoute("TestPlugint1", "TestPlugin/t1", new { controller = "TestPlugin", action = "t1" });
            });
        }

        public void PluginConfigureServices(IServiceCollection services)
        {

            services.AddMvc().AddApplicationPart(typeof(TestPluginController).GetTypeInfo().Assembly).AddControllersAsServices();
        }

    }
}

файл: Controllers / TestPluginController.cs

namespace EVS.TestPlugin.Controllers
{
    public class TestPluginController : Controller
    {
        public IActionResult Index()
        {
            return Content("<h1>TestPluginController</h1>");
        }

        public IActionResult t1()
        {
            return View("test");
        }
    }
}

файл: просмотрs / test.cshtml

@{
    Layout = null;
}

`.cshtml` test view

Плагины не включены в решение, но они загружаются динамически в зависимости от того, находятся ли они в папке для них.

Проблема: я могу соответственнодобавить контроллеры как (EVS.TestPlugin.PluginConfigureServices (...)) и MapRoute (EVS.TestPlugin.PluginConfigure (...)) Однако, как я могу также добавить контекст представлений?Поэтому это будет: ~/PluginName/Views/ViewName.cshatml

РЕДАКТИРОВАТЬ

Я нашел это ( ссылка ), но это не совсем то, что мне нужно.Это частично решает проблему, потому что это работает, только если представление скомпилировано.

РЕДАКТИРОВАТЬ 2

На мгновение я решил, добавив ссылку на представления на плагины csprojследующим образом:

<ItemGroup>
    <EmbeddedResource Include="Views\**\*.cshtml"/>
    <Content Remove="Views\**\*.cshtml" />
</ItemGroup>
<PropertyGroup>
    <RazorCompileOnBuild>false</RazorCompileOnBuild>
</PropertyGroup>

В исходном проекте:

// p is a Instance of plugin
foreach(IPlugin p in Plugins.Select((x) => x.Value))
    services.Configure<RazorViewEngineOptions>(options =>
    {
        options.FileProviders.Add(
                    new EmbeddedFileProvider(p.GetType().GetTypeInfo().Assembly));
    });

Это не решает мою проблему, потому что файлы .cshtml четко видны в файле плагина, что мне нужночтобы иметь возможность добавлять представления из сборки pluginname.views.dll или другим способом, важно, чтобы представления были скомпилированы

РЕДАКТИРОВАТЬ 3

Хорошие новости, используяILSpy Я проанализировал файл PluginName.Views.dll и обнаружил, что он реализует RazorPage<object>

С помощью следующего кода я подтвердил, что могу инициализировать все кэши, которые cono RazorPage<object>, что позволяет мне иметь экземплярыобъекты, которые создают представление

foreach (string dllview in Views.Select((x) => x.Key))
{
    PluginLoader loader = PluginLoader.CreateFromAssemblyFile(dllview, sharedTypes: new[] { typeof(RazorPage<object>) });
    foreach (RazorPage<object> RazorP in loader.LoadDefaultAssembly().GetTypes().Where(t => typeof(RazorPage<object>).IsAssignableFrom(t)).Select((x) => (RazorPage<object>)Activator.CreateInstance(x)))
    {
        // i need a code for add a RazorPagein the in RazorViewEngine, or anywhere else that allows register in the context

        System.Diagnostics.Debug.WriteLine(RazorP.GetType().ToString());
        /*  - output 
            AspNetCore.Views_test
            AspNetCore.Views_TestFolder_htmlpage

            as you can see is the folder structure

            - folder tree:
            Project plugin folder
                Views
                    test.cshtml
                    TestFolder
                        htmlpage.cshtml

        */
    }
}

Решено

Благодаря всему, что я решил, похоже, есть проблема с

var assembly = ...;
services.AddMvc()
    .AddApplicationPart(assembly)

, который кто-то забыл дажепоставь заводскую часть бритвы

скомпилироватьdRazorAssemblyApplicationPartFactory

Я решил, что

services.AddMvc().ConfigureApplicationPartManager(apm =>
    {
    foreach (var b in new CompiledRazorAssemblyApplicationPartFactory().GetApplicationParts(AssemblyLoadContext.Default.LoadFromAssemblyPath(".../ViewAssembypath/file.Views.dll")))
        apm.ApplicationParts.Add(b);
    });

Кроме того, я опубликовал библиотеку, которая делает все эффективно

NETCore.Mvc.PluginsManager

Ответы [ 2 ]

0 голосов
/ 02 января 2019

благодаря всему, что я решил, похоже, есть проблема с

var assembly = ...;
services.AddMvc()
    .AddApplicationPart(assembly)

, кто-то забыл даже поставить фабрику деталей бритвы

CompiledRazorAssemblyApplicationPartFactory

Я решил, что

services.AddMvc().ConfigureApplicationPartManager(apm =>
    {
    foreach (var b in new CompiledRazorAssemblyApplicationPartFactory().GetApplicationParts(AssemblyLoadContext.Default.LoadFromAssemblyPath(".../ViewAssembypath/file.Views.dll")))
        apm.ApplicationParts.Add(b);
    });

, кроме того, я опубликовал библиотеку, которая делает все эффективно

NETCore.Mvc.PluginsManager

0 голосов
/ 16 октября 2018

Вы можете добавить собственные пути поиска, создав поставщика файлов и добавив его в метод StartUp.ConfigureServices (), например:

IFileProvider myFileProvider = new PhysicalFileProvider("C:/Some/File/Location");
services.AddMvc().AddRazorOptions(opt =>
                        {
                            opt.FileProviders.Add(myFileProvider);
                        });
...