Тематические RazorPages в Dotnet Core 2.1 - PullRequest
0 голосов
/ 26 мая 2018

В настоящее время я пытаюсь реализовать тематический сайт, используя Razor Pages в dotnetcore 2.1, но у меня возникли некоторые затруднения / путаница с тем, почему страницы не загружаются.

Каждый запрос к сайту приводит к значению темыбыть установленным на основе доступного домена, по умолчанию используется тема «По умолчанию», которая хранится в 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;
    }

КакВы можете видеть, что я пытаюсь загрузить страницы (поскольку каждая тема может иметь совершенно разный макет, а не просто изменяющийся CSS) из /Pages/Themes/{THEME_NAME} ... вместо /Pages/, за исключением общей папки верхнего уровня /Pages/Shared для таких вещей, как частичные для сценариев проверки, которые могут существовать во всех темах.

Я не хочу, чтобы были какие-либо другие страницы непосредственно под /Pages, такие как /Pages/Index.cshtml, поскольку КАЖДЫЙ запрос должен заканчиваться внутриодна из папок тем как имеющая тему является обязательной.

Я добавил следующее к своему Startup.cs

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

Я могу установить точку останова этого кода на fПервая загрузка, так что я знаю, что она зарегистрирована, однако, если я запускаю сайт и получаю 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

Может кто-нибудь предложить мне какое-либо понимание или помочь с этим?

Возможно, мне нужно изменить какую-то маршрутизацию, чтобы включить тему, или я упускаю что-то важное, похоже, что места просмотра, которые я установил в ThemeViewLocationExpander.ExpandViewLocations(), никогда не используются.

Тамэто много мультитенантных вещей, о которых я читал для DNC 2.1, но это либо для MVC, а не RazorPages, либо реализует только страницы CSS / _Layout.cshtml внутри папок тем и использует страницы по умолчанию в /Pages/ для макета (я пытаюсь иметь индивидуальные реализации всех страниц в каждой папке темы)

Редактировать:

Я решил, что было бы разумнее сохранить /Pages/Index.cshtml и другиестраниц в папке верхнего уровня и используйте это как «Тема» по умолчанию, тогда любые новые темы будут использовать эти страницы, если только они не будут переопределены внутри их папки /Pages/Themes/{THEME_NAME}.

Я реализовал это, но все еще нахожусь напотеря в том, почему страница загружается из /Pages/Index.cshtml, даже если задано значение темы и в папку viewLocations добавлена ​​папка темы.

Редактировать 2:

Протестировал его и с установленной темой он определенно использовал правильную страницу макета в папке темы.Например, с темой «Fresh» при загрузке https://localhost:44352/ загружается страница макета /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

Редактировать 3:

Вот ссылка на github для упрощенной версии проекта, которая демонстрирует мою проблему.https://github.com/BenMaxfield/ThemeTest

Чтобы протестировать его, просто запустите приложение, и вы должны увидеть, что оно загружает макет темы DARK, но содержимое индекса DEFAULT.

Чтобы перейти к теме ПО УМОЛЧАНИЮ, найдите метод PopulateValues в ThemePageViewLocationExpander и установите context.Values[ThemeKey] = string.Empty;

Редактировать 4

У меня естьзаметил, что ThemePageViewLocationExpander.ExpandViewLocations - это каждый вызов только для частичных файлов, и никогда для реальных страниц с кодом позади.

Это объясняет, почему для темы была загружена правильная страница _Layout.cshtml, а правильный Index.cshtml файл былнет (так как /Pages/Index.cshtml является страницей с кодом позади и имеет объявление @page - т.е. оно не является частичным)

Чтобы обойти это хакерским способом, я создал новую папку /Pages/Views/ иположить частичный .cshtml, который соответствует каждой из @page страниц на верхнем уровне /Pages/,

, например, у меня теперь есть /Pages/Index.cshtml (не частичный) и /Pages/Views/Index.cshtml (частичный).

Внутри /Pages/Index.cshtml Я добавил <partial name="Index" model="@Model"/> для загрузки соответствующего частичного из новой папки /Pages/Views/.

Поскольку сейчас идет загрузка, вызывается частичный ThemePageViewLocationExpander.ExpandViewLocations, и яможет затем переопределить местоположение представления для этого на основе данного ключа темы (если присутствует).

Это означает, что все запросы к /Index будут загружать OnGet() из /Pages/Index.cshtml, что впоследствии загружает частичное в его представление, которое я могу при желании переопределить, добавив еще один Index.cshtml частичный внутри /Themes/{THEME_NAME}/Views/.

Вот мое текущее переопределение расположения для ThemePageViewLocationExpander.ExpandViewLocations

            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)
...