ASP.NET Core MVC 查看组件搜索路径

Mir*_*rek 6 c# asp.net-core asp.net-core-2.2

在此处的文档中: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}
Run Code Online (Sandbox Code Playgroud)

如何在此处添加另一条路径?

我想将我的视图组件及其各自的控制器放在一个名为 components 的项目文件夹中。

/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}
Run Code Online (Sandbox Code Playgroud)

我的动机:

我发现我的视图组件有自己的 JS 和 CSS 文件。我将所有 JS 捆绑并最小化在一个中site.min.js,所有 CSS 捆绑并最小化在它们的site.min.css. JS 总是类似$(function() { ... }),而 CSS 总是以一种顺序无关紧要的方式编写,因此在不知道顺序的情况下捆绑所有内容不是问题。

其中一些视图组件具有 javascripts,可以更改它们在服务器上的状态,例如对控制器操作的 AJAX 调用,该操作返回一些 JSON 或整个视图组件的 HTML。

由于控制器只是一个 C# 类,它们可以位于任何文件夹中,但是将带有相关 AJAX 操作的控制器移动到“视图”文件夹中感觉很愚蠢。

最后,我想要一个像这样的“组件”(不是真正的“视图组件”):

/Components/{View Component Name}/{View Name}
Run Code Online (Sandbox Code Playgroud)

Mir*_*rek 10

因此,在深入研究 aspnetcore 存储库一个小时后,我发现该组件的搜索路径是硬编码的,然后与普通视图搜索路径相结合。

// {0} is the component name, {1} is the view name.
private const string ViewPathFormat = "Components/{0}/{1}";
Run Code Online (Sandbox Code Playgroud)

然后将此路径发送到视图引擎

result = viewEngine.FindView(viewContext, qualifiedViewName, isMainPage: false);
Run Code Online (Sandbox Code Playgroud)

然后视图引擎使用可配置的视图路径生成完整路径。

  • Views/Shared/Components/Cart/Default.cshtml
  • Views/Home/Components/Cart/Default.cshtml
  • Areas/Blog/Views/Shared/Components/Cart/Default.cshtml

如果你想把你的视图组件放到我想要的名为“Components”的根文件夹中,你可以做这样的事情。

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);        
});
Run Code Online (Sandbox Code Playgroud)

在我看来这有点丑陋。但它有效。

您也可以像这样编写自己的扩展器。

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) {}
    }
}
Run Code Online (Sandbox Code Playgroud)

在 Startup.cs 中

services.Configure<RazorViewEngineOptions>(o =>
{
    o.ViewLocationExpanders.Add(new ComponentViewLocationExpander());   
});
Run Code Online (Sandbox Code Playgroud)