Blazor - 多引导/多租户

Posted

技术标签:

【中文标题】Blazor - 多引导/多租户【英文标题】:Blazor - Multi bootstrap / Multitenant 【发布时间】:2022-01-04 05:49:27 【问题描述】:

有没有更优雅的方法可以在一个项目中将 2 个 bootsraps/css 混合在一起?

我有一个 Blazor 应用程序(服务器预渲染),它有 2 个区域:

客户的最终用户(订购服务) 管理员(管理库存、价格...) - 仅适用于管理员用户

例如,我使用 bootstrap 5 开发了 Admin 部分(实际上我使用了带有自己的 bootstrap 的 MudBlazor)。

我需要网站的“最终用户”部分,其中将使用完全不同的引导程序 (https://themes.getbootstrap.com/product/space-multipurpose-responsive-template/)。

我可以将 2 个网站拆分为 2 个不同的“网络项目”,但客户更喜欢使用单个应用程序,我还没有找到文档示例如何实现这一点,所以我将 _Host.cshtml 更改为“catch”管理页面(并将它们指向页面Admin.cshtml)

@page "/"
@namespace MultiAreaDemo.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@
    Layout = null;


@if (Request.Query["admin"].FirstOrDefault() == "1")

    Html.RenderPartial("Admin.cshtml", null, ViewData);
    return;


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MultiAreaDemo - End user</title>
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/space-enduser/bootstrap.min.css" />
    <link href="MultiAreaDemo.styles.css" rel="stylesheet" />
</head>
.....

并创建了 Admin.cshtml 页面(指向“admin”引导 css):

@page "/admin"
@namespace MultiAreaDemo.Pages.Admin
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@
    Layout = null;


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MultiAreaDemo - ADMIN </title>
    <base href="~/" />
    <link rel="stylesheet" href="css/admin/bootstrap.min.css" />
</head>
<body>
    <component type="typeof(App)" render-mode="ServerPrerendered" />

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss">????</a>
    </div>

    <script src="_framework/blazor.server.js"></script>
</body>
</html>

所有“admin”页面都需要以“admin”为前缀。例如:

@page "/admin"
<h3>AdminHome</h3>
....

因此页面 https://localhost:44398/admin 正在使用 css/admin/bootstrap.min.css 而 https://localhost:44398/ 正在使用 css/bootstrap/space-enduser/bootstrap.min.css

希望对您有所帮助。如果有人知道更优雅的方式,我将不胜感激。

【问题讨论】:

这可以通过对用户和管理页面使用不同的布局非常简单地完成。如所选答案所示,您真的不需要动态 css 加载器的所有额外复杂性。有关详细信息,请参阅blazor-university.com/layouts/using-layouts @Roberto,您是说问题中描述的 _Host.cshtml 和 Admin.cshtml 'customisation' 吗? 【参考方案1】:

您可以切换 CSS - 以及标题中的几乎任何其他内容 - 如下所示:

如下定义你的 Css 链接,给它一个 id:

   <link id="dynamicCssLink" rel="stylesheet" href="/css/site.css" />

定义一些包含在您网站中的 JS 代码 - 我通常使用 site.js:

window.DynamicCss = 
   setCss: function (elementId, url) 
        var link = document.getElementById(elementId);
        if (link === undefined) 
            link = document.createElement(elementId);
            link.id = elementId;
            document.head.insertBefore(link, document.head.firstChild);
            link.type = 'text/css';
            link.rel = 'stylesheet';
        
        link.href = url;
        return true;
    

为 JS 互操作代码定义一个类:

    public class InteropLibrary
    
        protected IJSRuntime JSRuntime  get; 

        public InteropLibrary(IJSRuntime jsRuntime)
            => JSRuntime = jsRuntime;

        public ValueTask<bool> SetDynamicCss(string elementId, string url)
          => JSRuntime.InvokeAsync<bool>("DynamicCss.setCss", elementId, url);
    

在服务中注册

builder.Services.AddScoped<InteropLibrary>();

创建一个替代site.css。我的 - site-black.css - 看起来像这样:

@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');

html, body 
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    background-color:black !important;
    color: white !important;

....

我的测试Index 页面如下所示:

@page "/"

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<div class="m-2">
    <button class="btn @this.buttonColour" @onclick="SwitchCSS">@this.buttonLabel</button>
</div>

@code 
    [Inject] private InteropLibrary? interopLibrary  get; set; 


    private bool isDark;
    private string css => isDark ? "/css/site-black.css" : "/css/site.css";
    private string buttonLabel => isDark ? "Switch To Light" : "Switch To Dark" ;
    private string buttonColour => isDark ? "btn-light" : "btn-dark" ;

    private async Task SwitchCSS()
    
        this.isDark = !this.isDark;
        await interopLibrary!.SetDynamicCss("dynamiccsslink", this.css);
    

在索引页和计数器页之间切换样式表的示例实现

Layout.razor:

@inherits LayoutComponentBase

..... Mark-up

@code 
    [Inject] private InteropLibrary? interopLibrary  get; set; 

    private string _stylesheet = "/css/site.css";

    protected async override Task OnAfterRenderAsync(bool firstRender)
    
        await interopLibrary!.SetDynamicCss("dynamiccsslink", _stylesheet);
        await base.OnInitializedAsync();
    

DarkLayout.razor

@inherits LayoutComponentBase

..... Mark-up

@code 
    [Inject] private InteropLibrary? interopLibrary  get; set; 

    private string _stylesheet = "/css/dark-site.css";

    protected async override Task OnAfterRenderAsync(bool firstRender)
    
        await interopLibrary!.SetDynamicCss("dynamiccsslink", _stylesheet);
        await base.OnInitializedAsync();
    

索引

@page "/"
@layout MainLayout
<PageTitle>Index</PageTitle>
.....

计数器

@page "/counter"
@layout DarkLayout

<PageTitle>Counter</PageTitle>
....

【讨论】:

非常感谢您的提示。我假设,对于“管理员”和“最终用户”页面,您需要在 _Hosts.cshtml @if (Request.Query["admin"].FirstOrDefault() == "1") Html.RenderPartial("Admin.cshtml", null, ViewData); return; 中拥有代码,而不是创建新的布局,在那里我可以将您的解决方案与动态 Js 一起使用。或者您有什么提示,如何“拆分”“管理员”和“最终用户”页面? 不,使用 Blazor 布局。请参阅我的更新答案。

以上是关于Blazor - 多引导/多租户的主要内容,如果未能解决你的问题,请参考以下文章

什么是多租户模式?

多租户和多应用怎么对应

Apache Pulsar 之企业级特性-多租户介绍

什么是多租户saas架构设计

多租户改造

Serenity框架官方文档翻译3.2(多租户)