具有 API 网关和微服务的 Blazor 服务器指南

Myl*_*Rip 9 architecture microservices api-gateway blazor blazor-server-side

到目前为止,我还没有找到有关将 Blazor Server(不是WebAssembly)与 API 网关和微服务结合使用的指南。讨论这些 Blazor 以及 API 网关和微服务的文章总是提到 Blazor WebAssembly (Wasm)。(是否假设 Blazor Server 应用程序不会使用微服务?此外,就其价值而言,选择 Blazor Server 而不是 Blazor WebAssembly 的原因是为了更好地保护知识产权。)

\n\n

无论如何...我想知道 Blazor Server 应用程序是否应该位于网关前面,通过网关将其内部 API 调用发送到网关后面的微服务,例如 \xe2\x80\xa6

\n\n

[浏览器] ----(SignalR)--- [Blazor 服务器应用程序] ----(https)---- [API 网关] ----(http)---- [微服务]

\n\n

或者将应用程序放在网关后面,让 SignalR 连接隧道通过网关,这样更有意义吗\xe2\x80\xa6

\n\n

[浏览器] ----(SignalR)---- [API 网关] ----(SignalR)---- [Blazor 服务器应用程序] ----(http)---- [微服务]

\n\n

请记住在建立 SignalR 连接之前应用程序在浏览器中的初始加载。需要单独处理吗?它会影响上面给出的选项的选择吗?我缺少更好的解决方案吗?

\n

Xan*_*iff 5

我们使用 Blazor 服务器端作为在 Azure Service Fabric(本身是无状态 ASP.NET Core 服务)中运行的一组微服务的前端,因此这是一个完全合法的场景。我们的整个应用程序在 Azure 云中运行,因此我将使用其产品来描述我们的实现。

为了更好地分离问题并更容易地保护互联网边界,我们为公共 API 和 SignalR 提供了两个单独的服务。因此,API 网关可以充当安全边界,因为它可以处理 HTTPS 卸载、位于面向公众的子网上并路由到虚拟网络上的内部服务。然后,提供 SignalR 访问的服务在应用程序网关实例后面的面向公众的子网上运行(用于防火墙 + 服务路由功能)。

因此,我们将这两项服务设置如下:

信号服务

[浏览器] -- (SignalR) -- [Azure 应用程序网关] -- [Azure Service Fabric - Blazor 服务器端应用程序] -- [SF 服务远程处理] -- [微服务]

接口服务

[浏览器] -- (https) -- [Azure API 管理] -- (http) -- [Azure Service Fabric - ASP.NET Core API] -- [SF 服务远程处理] -- [微服务]

微服务陷阱 - 数据保护

特别是在支持身份验证时,ASP.NET Core 在内部设置一些密钥来加密 Blazor 会话中使用的状态。在微服务场景中,除非您在网络堆栈(负载均衡器、网关、路由器等)中一直有粘性路由,以确保所有请求始终到达同一个实例(并且可能您的实例不会被重建)并在你不注意的时候转移到其他地方),你将会遇到关于未能取消对状态的保护的模糊且无益的错误。

修复非常简单 - 在 ASP.NET Core 服务的 Startup.cs 中,确保services.AddDataProtection();正确设置和配置。由于我们使用的是 Service Fabric,因此我们使用了一个非常适合此目的的第三方库。要使用,请将 NuGet 包安装SoCreate.AspNetCore.DatapProtection.ServiceFabric到 ASP.NET Core 服务,然后将以下内容放入 Startup.cs 的方法中ConfigureServices()

public void ConfigureServices(IServiceCollection services)
{
  //...
  services.AddDataProtection().PersistKeysToServiceFabricDistributedCache(opt => {
    //Unique for this ASP.NET Core microservice, don't use a new GUID each time or you'll be back where you started without a single store for all the services
    opt.CacheStoreId = new Guid("b87d03b5-f8d1-456f-966d-11d2c4d9774d"); 

    //Specifically points to the service to use - if not set, it'll be automatically discovered
    opt.CacheStoreServiceUri = new Uri("fabric:/MyApplication/DataProtectionStore");   });
  //...
}
Run Code Online (Sandbox Code Playgroud)

您可以在后一种方法上指定其他选项来标识它应使用的特定服务和唯一 ID(以便该服务可以在应用程序之间共享),但如果它位于同一应用程序中并且您没有指定这些选项,它会自己找到它。

然后创建一个有状态服务实例,SoCreate.Extensions.Caching.ServiceFabric从 NuGet 安装到反映服务名称的文件中,并将其继承替换为 ,StatefulService而不是继承自DistributedCacheStoreService。删除服务中的其他所有内容,但设置更新的构造函数。在名为“DataProtectionStore”的服务中,您的DataProtectionStore.cs文件应如下所示:

using System.Fabric;
using SoCreate.Extensions.Caching.ServiceFabric

namespace DataProtectionStore
{
  internal sealed class DataProtectionStore : DistributedCacheStoreService
  {
    protected override int MaxCacheSizeInMegabytes => 500; //Optional

    public DataProtectionStore(StatefulServiceContext context) : base(context, message => ServiceEventSource.Current.ServiceMessage(context, message))
    {
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到特定于在“网络场”或微服务/分布式环境中托管 ASP.NET Core 的其他有用指南。

  • 谢谢 Xaniff,您花时间写出如此详细而彻底的答案!在特定上下文中对其进行描述以帮助实施也是非常值得赞赏的。我目前没有使用 Service Fabric,但当我横向扩展时,我将需要使用 Service Fabric 或 Kubernetes。这正是在使用新技术时通常很难找到的建议! (2认同)