我想在MVC 6 Web启动项目的单独程序集中定义视图组件(ASP.NET MVC 6中的新组件),以便我可以在多个Web项目中重用它们。示例解决方案可能如下所示:
我创建了一个新的类库(Package)并在其中创建了一个视图组件。我还在嵌套文件夹约定之后创建了视图。我的BookStore.Components
项目如下所示:
当我尝试从我的web项目中调用此视图组件时:
@Component.Invoke("BookOfTheMonth")
...我的内容正文出现了500错误。似乎发现了ViewComponent类,但组件的剃刀视图不是。
我还尝试扩展DefaultViewComponentDescriptorProvider
,以便可以发现BookStore.Components
程序集中的视图组件:
public class AssemblyProvider : IAssemblyProvider
{
public IEnumerable<Assembly> CandidateAssemblies
{
get
{
yield return typeof(AssemblyProvider).Assembly;
yield return typeof(BookStore.Components.BookOfTheMonthViewComponent).Assembly;
}
}
}
builder.RegisterType<AssemblyProvider>()
.AsImplementedInterfaces();
builder.RegisterType<DefaultViewComponentDescriptorProvider>()
.AsImplementedInterfaces();
我不确定是否需要注册DefaultViewComponentDescriptorProvider
以上,所以我尝试使用和不使用它,但我仍然在调用视图组件的页面上出现500错误。
如何调用与MVC6 Web项目位于单独程序集中的视图组件?
答案 0 :(得分:22)
更新2017-03-09
使用MS Build在Visual Studio 2017中发生了一些变化。幸运的是,它更简单。以下是如何使其工作:
在外部程序集中,将其添加到csproj文件中:
<ItemGroup>
<EmbeddedResource Include="Views/**/*.cshtml" />
</ItemGroup>
在主Web项目中,添加此NuGet包:
Microsoft.Extensions.FileProviders.Embedded
然后在“启动”中,将外部程序集添加到“文件提供程序”列表中:
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
# Prior to .Net Standard 2.0
# typeof(SampleClassInAssembly).GetTypeInfo().Assembly
));
});
我现在暂时留下原来的答案,以防人们仍在尝试使用旧版本的.Net Core和project.json
。
=============================================== =================
以下是实现此目的的步骤。
在网络项目的CompositeFileProvider
中注册Startup.cs
:
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProvider = new CompositeFileProvider(
new EmbeddedFileProvider(
typeof(BookOfTheMonthViewComponent).GetTypeInfo().Assembly,
"BookStore.Components"
),
options.FileProvider
);
});
CompositeFileProvider
和EmbeddedFileProvider
都是新的,因此您需要从aspnetvnext
NuGet Feed中获取这些内容。我这样做是通过添加这个来源:
在project.json
中添加依赖项:
"Microsoft.AspNet.FileProviders.Composite": "1.0.0-*",
"Microsoft.AspNet.FileProviders.Embedded": "1.0.0-*",
最后,将其添加到project.json
程序集的Components
:
"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
答案 1 :(得分:1)
我对Github进行了一些研究,发现Razor引擎(link)使用PhysicalFileProvider
(link)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
。
答案 2 :(得分:0)
自 .NetCore v3.x 起:
it("Should NOT render WebFeatures in small screen", () => {
jest.spyOn(window.screen, "width", "get").mockReturnValue(1000);
const wrapper = mount(<YourComponent />);
expect(wrapper.find("WebFeatures").exists()).toBe(false);
});
it("Should render WebFeatures in large screen", () => {
jest.spyOn(window.screen, "width", "get").mockReturnValue(1001);
const wrapper = mount(<YourComponent />);
expect(wrapper.find("WebFeatures").exists()).toBe(true);
});
nuget程序包Microsoft.Extensions.FileProviders.Embedded
nuget程序包Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation
,例如:.AddRazorRuntimeCompilation()
services.AddMvc().AddRazorRuntimeCompilation()
添加此内容:
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
));
});
你很好。