我目前正在尝试使用dotnetcore 2.1中的Razor Pages实现一个可主题化的网站,但是为什么页面无法加载会遇到一些麻烦/困惑 .

对站点的每个请求都会导致基于访问的域设置主题值,默认情况下,主题为“Default”,存储在每个请求的RouteData中 .

我已实现以下 ThemeViewLocationExpander

public class ThemeViewLocationExpander : IViewLocationExpander
{
    private const string ValueKey = "Theme";

    public void PopulateValues(ViewLocationExpanderContext context)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        context.Values[ValueKey] = (context.ActionContext.RouteData.Values["tenant"] as Tenant)?.Theme;
    }

    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (viewLocations is null)
        {
            throw new ArgumentNullException(nameof(viewLocations));
        }

        context.Values.TryGetValue(ValueKey, out string theme);

        if (!string.IsNullOrEmpty(theme))
        {
            viewLocations = new[] {
                $"/Pages/Themes/{theme}/{{1}}/{{0}}.cshtml",
                $"/Pages/Themes/{theme}/Shared/{{0}}.cshtml",
                $"/Pages/Shared/{{0}}.cshtml",
            };
        }

        return viewLocations;
    }

你可以看到我试图从 /Pages/Themes/{THEME_NAME} 而不是 /Pages/ 加载页面(因为每个主题可能有一个完全不同的布局,而不仅仅是不同的CSS),但顶级共享文件夹 /Pages/Shared 除外可能存在于所有主题中的验证脚本的部分 .

我不希望在 /Pages 之下直接有任何其他页面,例如 /Pages/Index.cshtml ,因为每个请求都应该在主题文件夹中结束,因为主题是强制性的 .

我已将以下内容添加到我的 Startup.cs

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

我可以在第一次加载时断开此代码,所以我知道它已注册,但是如果我运行该站点并且 https://localhost:44352/ 它加载 /Pages/Index.cshtml 时应该加载 /Pages/Themes/Default/Index.cshtml .

如果我删除 /Pages/Index.cshtml 并运行我得到的网站

This localhost page can’t be found
No webpage was found for the web address: https://localhost:44352/
HTTP ERROR 404

任何人都可以向我提供任何见解或帮助吗?

也许我需要修改一些路由来合并主题,或者我错过了一些重要的东西,似乎我在_2355414中设置的视图位置从未被使用过 .

我已经阅读了很多关于DNC 2.1的多租户内容,但它要么是MVC而不是RazorPages,要么只在主题文件夹中实现CSS / _Layout.cshtml页面,并使用 /Pages/ 下的默认页面进行布局(我是试图在每个主题文件夹中包含所有页面的单独实现)

Edit:

我已经决定将 /Pages/Index.cshtml 和其他页面保留在顶级文件夹中更有意义并将其用作默认'Theme'然后任何新主题将使用这些页面,除非在其 /Pages/Themes/{THEME_NAME} 文件夹中特别重写 .

我已实现了这一点,但即使设置了主题值并且 viewLocations 已添加主题文件夹,我仍然不知道为什么页面从 /Pages/Index.cshtml 加载 .

Edit 2:

测试过它并使用主题设置它肯定在主题文件夹中使用了正确的布局页面 . 例如,当我加载 https://localhost:44352/ 主题'Fresh'时,加载了布局页面 /Pages/Themes/Fresh/Shared/_Layout.cshtml ,但 Index.cshtml/Pages/Index.cshtml 加载 /Pages/Themes/Fresh/Index.cshtml .

此时 viewLocations 是:

/Pages/Themes/Fresh/{1}/{0}.cshtml
/Pages/Themes/Fresh/Shared/{0}.cshtml
/Pages/Shared/{0}.cshtml
/Pages/{1}/{0}.cshtml
/Pages/Shared/{0}.cshtml
/Views/Shared/{0}.cshtml

Edit 3:

这是一个github链接,用于简化版本的项目,演示了我遇到的问题 . https://github.com/BenMaxfield/ThemeTest

为了测试它,只需运行应用程序,您应该看到它加载了DARK主题布局,但是加载了DEFAULT索引内容 .

要交换到DEFAULT主题,请在 ThemePageViewLocationExpander 中查找 PopulateValues 方法并设置 context.Values[ThemeKey] = string.Empty;

Edit 4

我注意到 ThemePageViewLocationExpander.ExpandViewLocations 只是每个被调用的部分文件,而且从不用于带有代码的实际页面 .

这解释了为什么为主题加载了正确的 _Layout.cshtml 页面,但没有正确的 Index.cshtml 文件(因为 /Pages/Index.cshtml 是一个代码隐藏的页面并且具有 @page 声明 - 即它不是部分的)

为了解决这个问题,我已经创建了一个新的文件夹 /Pages/Views/ 并将 .cshtml 放在与_235545_顶层的每个 @page 页面相对应的位置 .cshtml

例如,我现在有 /Pages/Index.cshtml (非部分)和 /Pages/Views/Index.cshtml (部分) .

/Pages/Index.cshtml 内部我添加了 <partial name="Index" model="@Model"/> 以从新的 /Pages/Views/ 文件夹中加载相应的部分 .

由于现在加载了一个部分 ThemePageViewLocationExpander.ExpandViewLocations 被调用,然后我可以根据给定的主题键(如果存在)覆盖它的视图位置 .

这意味着对 /Index 的所有请求都将从 /Pages/Index.cshtml 加载 OnGet() ,随后在其视图中加载部分,我可以选择通过在 /Themes/{THEME_NAME}/Views/ 内添加另一个 Index.cshtml 部分来覆盖 .

这是我当前的 ThemePageViewLocationExpander.ExpandViewLocations 的viewlocation覆盖

viewLocations = new[] {
                $"/Themes/{theme}/{{0}}.cshtml",
                $"/Themes/{theme}/Views/{{0}}.cshtml",
                $"/Pages/Views/{{0}}.cshtml",
            }.Concat(viewLocations);

和示例文件夹结构:

.
├── Pages
|   ├── Index.cshtml (with code behind, called on localhost:45635/)
|   └── Views
|       └── Index.cshtml (partial)
└── Themes
|   ├── Dark
|      └── Views
|          └── Index.cshtml (partial)