我可以通过使用 Razor Pages 指定相对路径在分部视图中呈现另一个分部视图吗?

Can I render another partial view in a partial view by specifying relative path with Razor Pages?

我有一个结构如下的 Razor Pages 项目(无控制器):

从主 Index.cshtml 开始,我会根据主题名称呈现其内容的部分视图,例如:

@* Default will be replaced with theme name *@
<partial name="Themes\Default\HomeContent" />

HomeContent.cshtml 中,我想在其文件夹中渲染许多其他局部视图。但是这行不通:

<p>Content</p>

<partial name="_DefaultThemePartial" />

引擎只搜索这些位置(正确according to the documentation):

InvalidOperationException: The partial view '_DefaultThemePartial' was not found. The following locations were searched:

/Pages/_DefaultThemePartial.cshtml

/Pages/Shared/_DefaultThemePartial.cshtml

/Views/Shared/_DefaultThemePartial.cshtml

我也试过 <partial name="./_DefaultThemePartial" /><partial name=".\_DefaultThemePartial" /> 或尝试将它们放在名为 Shared 的子文件夹中(在默认文件夹中)。 None 个有效,仅搜索以上 3 个位置。

是否可以在不指定完整路径的情况下渲染这些部分?

我发布了a proposal here。与此同时,我发现您可以使用 IViewLocationExpander 扩展发现机制,但我几乎找不到任何有用的文档。

public class PartialViewLocationExpander : IViewLocationExpander
{
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        if (!context.Values.TryGetValue("FromView", out var fromView))
        {
            return viewLocations;
        }

        var folder = Path.GetDirectoryName(fromView) ?? "/";
        var name = context.ViewName;
        if (!name.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase))
        {
            name += ".cshtml";
        }

        var path = Path.Combine(folder, name)
            .Replace('\', '/');

        return viewLocations.Concat(new[] { path });
    }

    public void PopulateValues(ViewLocationExpanderContext context)
    {
        var ctx = context.ActionContext as ViewContext;
        if (ctx == null) { return; }

        var path = ctx.ExecutingFilePath;
        if (!string.IsNullOrEmpty(path))
        {
            context.Values["FromView"] = path;
            context.Values["ViewName"] = context.ViewName;
        }
    }
}

// Register
services.Configure<RazorViewEngineOptions>(options =>
{
    options.ViewLocationExpanders.Add(new PartialViewLocationExpander());
});

根据我的 GitHub issue 的回复,有一个更简单的解决方案,无需任何额外代码,只需在末尾添加 .cshtml

[...] This is by design. Partial view lookup is done in two ways:

  • By name

  • By file path

You've done the lookup by name (without file extension), if you want to use a relative path, make sure you specify the file extension.

<partial name="_DefaultThemePartial.cshtml" />