Итак, после часа копания в репозитории aspnetcore я обнаружил, что путь поиска компонента жестко задан , а затем объединен с обычными путями поиска.
// {0} is the component name, {1} is the view name.
private const string ViewPathFormat = "Components/{0}/{1}";
Этот путь затем отправляется в механизм просмотра
result = viewEngine.FindView(viewContext, qualifiedViewName, isMainPage: false);
Затем механизм просмотра создает полный путь, используя настраиваемые пути просмотра.
Views/Shared/<strong>Components/Cart/Default</strong>.cshtml
Views/Home/<strong>Components/Cart/Default</strong>.cshtml
Areas/Blog/Views/Shared/<strong>Components/Cart/Default</strong>.cshtml
Если вы хотите поместить компоненты вашего представления в корневую папку с именем «Компоненты», как я хотел, вы можете сделать что-то вроде этого.
services.Configure<RazorViewEngineOptions>(o =>
{
// {2} is area, {1} is controller,{0} is the action
// the component's path "Components/{ViewComponentName}/{ViewComponentViewName}" is in the action {0}
o.ViewLocationFormats.Add("/{0}" + RazorViewEngine.ViewExtension);
});
Это немного уродливо по моему мнению. Но это работает.
Вы также можете написать свой собственный расширитель, как это.
namespace TestMvc
{
using Microsoft.AspNetCore.Mvc.Razor;
using System.Collections.Generic;
public class ComponentViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
// this also feels ugly
// I could not find another way to detect
// whether the view name is related to a component
// but it's somewhat better than adding the path globally
if (context.ViewName.StartsWith("Components"))
return new string[] { "/{0}" + RazorViewEngine.ViewExtension };
return viewLocations;
}
public void PopulateValues(ViewLocationExpanderContext context) {}
}
}
А в Startup.cs
services.Configure<RazorViewEngineOptions>(o =>
{
o.ViewLocationExpanders.Add(new ComponentViewLocationExpander());
});