【问题标题】:The view 'Index' was not found from pluggin从插件中找不到视图“索引”
【发布时间】:2020-03-28 17:27:23
【问题描述】:

我告诉你,我有一个带有 netcore mvc 的应用程序,它从主项目的不同区域加载插件。

这很好用,但是在执行该区域时会引发以下错误:

处理请求时发生未处理的异常。

InvalidOperationException:未找到视图“索引”。搜索了以下位置: /Views/TestHome/Index.cshtml /Views/Shared/Index.cshtml /Pages/Shared/Index.cshtml

里面的区域叫做TestArea,但是并没有提升我的插件区的视图。

我的插件结构如下:

我的主项目结构如下:

Areas/Extensions/TestArea 文件夹中放置程序集,在 Areas/TestArea 文件夹中放置视图。

正如我提到的,加载插件并运行控制器,但执行它会抛出我之前暴露的错误。

我使用的代码如下:

PluginExtensions.cs

public static class PluginExtensions
{

    public static IMvcBuilder AddExtensions(this IMvcBuilder mvc)
    {
        List<string> extensionAssemblies = new List<string>();
        var serviceProvider = mvc.Services.BuildServiceProvider();
        var configuration = serviceProvider.GetService<IConfiguration>();
        var hostingEnvironment = serviceProvider.GetService<IWebHostEnvironment>();
        var logger = serviceProvider.GetService<ILoggerFactory>().CreateLogger<Startup>();
        List<string> extensionDirectories = EnumerateExtensionDirectories(serviceProvider).ToList();
        List<string> searchPatternList = new List<string>
        {
            "*Extension.Mvc.dll"
        };
        mvc.ConfigureApplicationPartManager(apm =>
        {
            foreach(var extensionDirectory in extensionDirectories)
            {
                for (int i = 0; i < searchPatternList.Count; i++)
                {
                    List<string> tempList = EnumerateExtensionAssemblies(extensionDirectory, searchPatternList[i]).ToList();
                    if (tempList != null && tempList.Count > 0)
                        extensionAssemblies.AddRange(tempList);
                }//for(int i=0;i< searchPatternList.Count; i++)
                foreach (var extensionPath in extensionAssemblies)
                {
                    var pluginAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(extensionPath);
                    var partFactory = ApplicationPartFactory.GetApplicationPartFactory(pluginAssembly);

                    foreach (var part in partFactory.GetApplicationParts(pluginAssembly))
                    {
                        apm.ApplicationParts.Add(part);
                    }

                    var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(pluginAssembly, throwOnError: true);
                    foreach (var assembly in relatedAssemblies)
                    {
                        if (assembly.FullName.ToLower().IndexOf("extension.mvc.views") >= 0)
                        {
                            **var compiledRazorAssemblyApplicationParts = new CompiledRazorAssemblyApplicationPartFactory().GetApplicationParts(AssemblyLoadContext.Default.LoadFromAssemblyPath(assembly.Location));**
                            foreach (var craapf in compiledRazorAssemblyApplicationParts)
                                apm.ApplicationParts.Add(craapf);
                        }
                        else
                        {
                            partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);
                            foreach (var part in partFactory.GetApplicationParts(assembly))
                            {
                                apm.ApplicationParts.Add(part);
                            }
                        }

                    }
                }


            }
        });
        return mvc;
    }}

Startup.cs

  public void ConfigureServices(IServiceCollection services)
    {
        services.AddSession(options =>
        {
            options.Cookie.Name = ".Matios.Session";
            options.IdleTimeout = TimeSpan.FromMinutes(30);
            options.Cookie.IsEssential = true;
        });
        services.AddControllersWithViews();
        services.AddResponseCaching();
        services.AddRazorPages();
        services.AddAntiforgery(options =>
        {
            options.Cookie.Name = ".Matios.Antiforgery";
        });
        var iMvc= services.AddMvc(options =>
        {
            options.Filters.Add(new SessionExpireAttribute());

            options.EnableEndpointRouting = true;
        })**.AddExtensions()**;
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }

最后我执行的 url 如下:http://localhost:5000/TestArea/TestHome/Index

你能帮帮我吗?

【问题讨论】:

  • 几件事....您在“插件”中定义了两次TestArea/TestHome/Index.cshtml,一次在您的网站中定义...。我不确定这是否可行。 .. 其次,据我所知,搜索位置是相对于当前工作目录的。因此,当您将内容放入“扩展”时,它将如何找到所需的内容?我会首先从网站中删除 TestArea 并将这些“参考”放在项目的根目录中,而不是放在任何文件夹中。
  • 另外你为什么要动态加载“插件”?我的意思是你已经将它们添加到主网站上......那么有什么意义呢?您不妨添加一个参考并省去自己的麻烦
  • 重点是动态加载程序集,否则我会直接引用而不是动态加载。
  • 是的,但是您将它们添加到主项目中......所以它违背了动态加载它们的目的......
  • 问题你能显示你的Test.ModuleExtension.Mvc项目中所有文件的图像吗?

标签: c# asp.net-core asp.net-core-mvc


【解决方案1】:

我能够通过执行以下操作来解决问题:

首先是插件: 我用我想要的区域创建了一个功能齐全的 MVC 网站。 在这种情况下,只是一个普通网站装饰 HomeController:

    [Area("TestArea")]
    public class HomeController : Controller

然后像这样移动TestArea下的“东西”:

第二次转换为 DLL: 像这样将“插件”转换为类库:

第三位主持人: 我创建了一个没有区域的 VANILLA 网站 像您一样添加了“插件程序集” 但是我将它们添加到项目的根目录中...... 像这样:

第四领域支持: 在这两个项目中,我在 Startup 类中添加了对区域的路由支持,如下所示:

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

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {//this was added to both projects
                endpoints.MapControllerRoute(
                    name: "areaDefault",
                    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

第五次更改插件扩展: 更改了您必须在当前目录中查看的 PluginExtensions 类,如下所示:

var extensionDirectories = new List<string> { Directory.GetCurrentDirectory() };

终于 我没有将“视图”添加到主机项目中......因为这些应该在插件的 dll 中编译...... 事实上,我什至没有添加区域文件夹......因为每个“区域插件”都应该控制它自己的“区域”。

结果如下: 请注意 URL 如何指向当前网站中不存在的区域...它是动态加载的! 万岁!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-11
    • 2016-04-10
    • 2011-01-17
    • 2010-11-25
    • 2018-09-04
    • 1970-01-01
    • 2012-10-06
    相关资源
    最近更新 更多