ASP.NET Core MVC Просмотр пути поиска компонентов - PullRequest
1 голос
/ 17 апреля 2019

В документации здесь: https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-2.2

Среда выполнения ищет представление по следующим путям:

/Views/{Controller Name}/Components/{View Component Name}/{View Name}
/Views/Shared/Components/{View Component Name}/{View Name}
/Pages/Shared/Components/{View Component Name}/{View Name}

Как я могу добавить другой путь здесь?

Я хотел бы, чтобы компоненты моего представления с соответствующими контроллерами находились в одной папке проекта с именами компонентов, подобных этой.

/Components/{View Component Name}/{View Name}

Моя мотивация:

Я обнаружил, что мои компоненты вида имеют свои собственные файлы JS и CSS. У меня все JS связаны и свернуты в один site.min.js, а все CSS связаны и свернуты в их site.min.css. JS всегда что-то наподобие $(function() { ... }), а CSS всегда пишутся так, что порядок не имеет значения, поэтому объединение всех без знания порядка не проблема.

Некоторые из этих компонентов представления имеют JavaScript, которые изменяют свое состояние на сервере, например AJAX-вызов к действию контроллера, который возвращает некоторый JSON или весь HTML-код компонента представления.

Поскольку контроллеры являются просто классами C #, они могут находиться в любой папке, но глупо перемещать контроллер с соответствующим действием AJAX в папку «Views».

В конце я хотел бы иметь «компонент» (на самом деле не только «компонент просмотра»), подобный этому:

/Components/SomeViewComponent/Default.cshtml
/Components/SomeViewComponent/SomeViewComponentController.cs
/Components/SomeViewComponent/SomeViewComponent.cs
/Components/SomeViewComponent/SomeViewComponent.css
/Components/SomeViewComponent/SomeViewComponent.js
/Components/SomeViewComponent/SomeViewComponent.en.resx
/Components/SomeViewComponent/SomeViewComponent.cs-CZ.resx

Ответы [ 2 ]

2 голосов
/ 17 апреля 2019

Итак, после часа копания в репозитории 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());   
});
1 голос
/ 17 апреля 2019

Вы можете добавить дополнительные просмотр форматов местоположения в RazorViewEngineOptions.Например, чтобы добавить путь, который удовлетворяет вашим требованиям, вы можете использовать что-то вроде этого:

services
    .AddMvc()
    .AddRazorOptions(o =>
    {
        // /Components/{View Component Name}/{View Name}.cshtml
        o.ViewLocationFormats.Add("/{0}.cshtml");
        o.PageViewLocationFormats.Add("/{0}.cshtml");
    });

Как видно выше, существуют различные свойства для просмотров (при использованииконтроллеры и действия) и просмотров страниц (при использовании Razor Pages).Также есть свойство для областей, но я оставил это в этом примере, чтобы оно было немного короче.

Недостатком этого подхода является то, что форматы местоположения вида не применяются только для просмотра компонентов.Например, при поиске вида Index внутри Home Razor теперь также будет искать Index.cshtml, находящийся в корне проекта.Это может быть хорошо, потому что это последнее найденное местоположение, и я ожидаю, что у вас не будет никаких представлений, лежащих в основе вашего проекта, но об этом, безусловно, стоит знать.

...