ASP.NET MVC 6:在单独的程序集中查看组件

我想在MVC 6 Web启动项目的单独程序集中定义视图组件(ASP.NET MVC 6中的新组件),以便我可以在多个Web项目中重用它们。 示例解决方案可能如下所示:

  • BookStore.Components (容纳常见视图组件)
  • BookStore.Web1 (引用BookStore.Components)
  • BookStore.Web2 (引用BookStore.Components)

我创建了一个新的类库(Package)并在其中创建了一个视图组件。 我还在嵌套文件夹约定之后创建了视图。 我的BookStore.Components项目如下所示:

在此处输入图像描述

当我尝试从我的Web项目中调用此视图组件时:

 @Component.Invoke("BookOfTheMonth") 

…我的内容正文出现了500错误。 似乎发现了ViewComponent类,但组件的剃刀视图却没有。

我还尝试扩展DefaultViewComponentDescriptorProvider以便可以发现BookStore.Components程序BookStore.Components视图组件:

定义了AssemblyProvider

  public class AssemblyProvider : IAssemblyProvider { public IEnumerable CandidateAssemblies { get { yield return typeof(AssemblyProvider).Assembly; yield return typeof(BookStore.Components.BookOfTheMonthViewComponent).Assembly; } } } 

使用Autofac注册的AssemblyProvider

 builder.RegisterType() .AsImplementedInterfaces(); builder.RegisterType() .AsImplementedInterfaces(); 

我不确定是否需要注册上面的DefaultViewComponentDescriptorProvider ,所以我尝试使用和不使用它,但我仍然在调用视图组件的页面上得到500错误。

如何从MVC6 Web项目中调用位于单独程序集中的视图组件?

更新2017-03-09

使用MS Build在Visual Studio 2017中发生了一些变化。 幸运的是,它更简单。 以下是如何使其工作:

在外部程序集中,将其添加到csproj文件:

    

在主Web项目中,添加此NuGet包: Microsoft.Extensions.FileProviders.Embedded

然后在Startup中,将外部程序集添加到文件提供程序列表中:

  services.Configure(options => { options.FileProviders.Add(new EmbeddedFileProvider( typeof(SampleClassInAssembly).Assembly # Prior to .Net Standard 2.0 # typeof(SampleClassInAssembly).GetTypeInfo().Assembly )); }); 

我现在暂时留下原来的答案,以防人们仍然试图使用旧版本的.Net Core和project.json

================================================== ==============

以下是使这项工作的步骤。

  • 确保组件程序集中的视图结构与Web项目相同。 请注意,我在问题中发布的屏幕截图中存在错误。
  • 在Web项目的Startup.cs中注册CompositeFileProvider

     services.Configure(options => { options.FileProvider = new CompositeFileProvider( new EmbeddedFileProvider( typeof(BookOfTheMonthViewComponent).GetTypeInfo().Assembly, "BookStore.Components" ), options.FileProvider ); }); 

CompositeFileProviderEmbeddedFileProvider都是新的,因此您需要从aspnetvnext NuGet提要中获取这些内容。 我这样做是通过添加这个来源:

在此处输入图像描述

project.json添加依赖项:

 "Microsoft.AspNet.FileProviders.Composite": "1.0.0-*", "Microsoft.AspNet.FileProviders.Embedded": "1.0.0-*", 

最后,将其添加到Components程序集的project.json中:

 "resource": "Views/**" 

这应该足以让这个工作。

这是一个有效的演示: https : //github.com/johnnyoshika/mvc6-view-components/tree/master

这个答案来自这里的讨论: https : //github.com/aspnet/Mvc/issues/3750

更新2016-01-15目前外部视图组件存在一个令人痛苦的问题。 您对视图cshtml文件所做的任何更改都不会自动重新编译。 即使强制Visual Studio清理和重建也不行。 您需要更改组件程序集中的.cs文件以触发视图重新编译,但看起来这将是将来要更正的内容。 这里解释了这个问题的原因: https : //github.com/aspnet/Mvc/issues/3750#issuecomment-171765303

我已经对Github做了一些研究,发现Razor引擎( 链接 )使用PhysicalFileProvider ( 链接 ) IFileInfo GetFileInfo(string subpath)方法来获取要编译的真实文件。

目前这种方法的实现

 public IFileInfo GetFileInfo(string subpath) { if (string.IsNullOrEmpty(subpath)) { return new NotFoundFileInfo(subpath); } // Relative paths starting with a leading slash okay if (subpath.StartsWith("/", StringComparison.Ordinal)) { subpath = subpath.Substring(1); } // Absolute paths not permitted. if (Path.IsPathRooted(subpath)) { return new NotFoundFileInfo(subpath); } var fullPath = GetFullPath(subpath); if (fullPath == null) { return new NotFoundFileInfo(subpath); } var fileInfo = new FileInfo(fullPath); if (FileSystemInfoHelper.IsHiddenFile(fileInfo)) { return new NotFoundFileInfo(subpath); } return new PhysicalFileInfo(_filesWatcher, fileInfo); } private string GetFullPath(string path) { var fullPath = Path.GetFullPath(Path.Combine(Root, path)); if (!IsUnderneathRoot(fullPath)) { return null; } return fullPath; } 

我们在这里可以看到绝对路径也是允许的, GetFullPath方法将路径与Root (主要的Web应用程序根路径)组合在一起。

所以我假设你无法从当前文件夹中打开ViewComponent