简体   繁体   中英

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

I have a Razor Pages project (no Controller) with structure like this:

在此处输入图像描述

From the main Index.cshtml , I would render a partial view for its content depend on the Theme name, for example:

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

In HomeContent.cshtml , I would like to render many other partial views within its folder. However this wouldn't work:

<p>Content</p>

<partial name="_DefaultThemePartial" />

The engine only searches these locations (correct 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

I have also tried <partial name="./_DefaultThemePartial" /> or <partial name=".\_DefaultThemePartial" /> or try putting them in a subfolder named Shared (within the Default folder). None of them works, only the above 3 locations are searched.

Is there anyway to render those partials without specifying the full path?

I posted a proposal here . In the meantime, I found out you can expand the discovery mechanism by using IViewLocationExpander but I barely found any useful documentation on it.

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());
});

From a response from my GitHub issue , there's a simpler solution without any extra code by adding the .cshtml at the end:

[...] 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" />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM