我可以通过使用 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" />
我有一个结构如下的 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" />