插件中的 ASP .NET Core MVC 2.1 mvc 视图

Gia*_*hia 6 c# asp.net-mvc plugins asp.net-core

我有一个问题困扰了我好几天。

正如我在 ASP .NET Core MVC 的插件中所做的那样,通过插件为我带来视图

我有这种情况

解决方案:电动汽车

  • 控制器
    • ...
  • 观看次数
    • ...
  • 插件
    • 这个文件夹包含一个插件dll
  • 其他文件夹...
  • 插件程序
  • 程序.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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

文件 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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

文件 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?}");
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在让我们举一个插件的例子

解决方案:EVS.TestPlugin

  • 控制器
    • 测试插件控制器.cs
  • 观看次数
    • 测试.cshtml
  • 测试插件

文件: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();
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

文件:控制器/TestPluginController.cs

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

        public IActionResult t1()
        {
            return View("test");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

文件:视图/test.cshtml

@{
    Layout = null;
}

`.cshtml` test view
Run Code Online (Sandbox Code Playgroud)

插件不包含在解决方案中,但它们会根据它们是否在一个文件夹中被动态加载。

问题:我可以相应地将控制器添加为 (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>
Run Code Online (Sandbox Code Playgroud)

在源项目上:

// 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));
    });
Run Code Online (Sandbox Code Playgroud)

这不能解决我的问题,因为.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

        */
    }
}
Run Code Online (Sandbox Code Playgroud)

解决了

感谢我解决的所有问题,似乎有问题

var assembly = ...;
services.AddMvc()
    .AddApplicationPart(assembly)
Run Code Online (Sandbox Code Playgroud)

有人甚至忘了把剃须刀零件工厂

CompiledRazorAssemblyApplicationPartFactory

我解决了

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

此外,我还发布了一个可以高效完成所有工作的库

NETCore.Mvc.插件管理器

Gia*_*hia 2

感谢我解决的所有问题,似乎有一个问题

var assembly = ...;
services.AddMvc()
    .AddApplicationPart(assembly)
Run Code Online (Sandbox Code Playgroud)

有人甚至忘记把剃须刀零件工厂

编译的RazorAssemblyApplicationPartFactory

我解决了这个问题

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

另外我发布了一个可以高效完成所有事情的库

NETCore.Mvc.PluginsManager