具有 API 网关和微服务的 Blazor 服务器指南
Posted
技术标签:
【中文标题】具有 API 网关和微服务的 Blazor 服务器指南【英文标题】:Guidance for Blazor Server with API Gateway and Microservices 【发布时间】:2020-08-24 08:17:26 【问题描述】:到目前为止,我还没有找到有关将 Blazor 服务器(不是 WebAssembly)与 API 网关和微服务一起使用的指导。讨论这些 Blazor 以及 API 网关和微服务的文章总是参考 Blazor WebAssembly (Wasm)。 (是否假设 Blazor Server 应用程序不会使用微服务?另外,就其价值而言,选择 Blazor Server 而不是 Blazor WebAssembly 的原因是为了更好地保护知识产权。)
无论如何... 我想知道 Blazor Server 应用程序是否应该位于网关前面,通过网关将其内部 API 调用发送到网关后面的微服务,就像这样...
[浏览器] ----(SignalR)--- [Blazor 服务器应用程序] ----(https)---- [API 网关] ----(http)---- [微服务]
或者将应用程序放在网关后面是否更有意义,让 SignalR 连接隧道通过网关,像这样......
[浏览器] ----(SignalR)---- [API 网关] ----(SignalR)---- [Blazor 服务器应用程序] ----(http)---- [微服务]
请记住在建立 SignalR 连接之前浏览器中应用程序的初始加载。需要分开处理吗?它会影响上面给出的选项的选择吗?我缺少更好的解决方案吗?
【问题讨论】:
【参考方案1】:我们使用 Blazor 服务器端作为在 Azure Service Fabric 中运行的一组微服务(本身是无状态的 ASP.NET Core 服务)的前端,因此这是一个完全合法的场景。我们的整个应用程序在 Azure 的云中运行,所以我将使用它的产品来描述我们的实现。
为了更好地分离关注点并更轻松地保护互联网边界,我们为公共 API 和 SignalR 提供了两个独立的服务。 API 网关因此充当安全边界,因为它可以处理 HTTPS 卸载、位于面向公众的子网上并路由到虚拟网络上的内部服务。然后,提供 SignalR 访问的服务在应用程序网关实例后面的面向公众的子网上运行(用于防火墙 + 服务路由功能)。
因此,我们将两个服务设置如下:
SignalR 服务
[浏览器] -- (SignalR) -- [Azure 应用程序网关] -- [Azure Service Fabric - Blazor 服务器端应用程序] -- [SF 服务远程处理] -- [微服务]
API 服务
[浏览器] -- (https) -- [Azure API 管理] -- (http) -- [Azure Service Fabric - ASP.NET Core API] -- [SF Service Remoting] -- [微服务]
微服务陷阱 - 数据保护
特别是在支持身份验证时,ASP.NET Core 在内部设置了一些密钥,用于加密 Blazor 会话中使用的状态。在微服务场景中,除非您的网络堆栈(负载均衡器、网关、路由器等)一直有粘性路由,以确保所有请求始终命中同一个实例(并且可能不会重建您的实例并在您不注意时转移到其他地方),您将遇到关于未能取消保护状态的模糊且无益的错误。
修复非常简单 - 在 ASP.NET Core 服务的 Startup.cs 中,确保设置 services.AddDataProtection();
并进行适当配置。由于我们使用的是 Service Fabric,因此我们使用了一个 third-party library,它非常适合此目的。要使用,请将 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"); );
//...
您可以在后一种方法上指定其他选项来标识它应该使用的特定服务和唯一 ID(因此服务可以在应用程序之间共享),但如果它在同一个应用程序中并且您没有指定这些选项,它会自己找到。
然后创建一个有状态服务实例,在反映服务名称的文件中从 NuGet 安装 SoCreate.Extensions.Caching.ServiceFabric
,并将其从 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))
您可以找到其他有关在“网络场”或微服务/分布式环境中托管 ASP.NET Core 的有用指南here。
【讨论】:
感谢 Xaniff 抽出宝贵时间写出如此详细而透彻的答案!非常感谢在特定上下文中描述它以帮助实现。我目前没有使用 Service Fabric,但随着我的横向扩展,我将需要使用它或 Kubernetes。这只是在使用新技术时通常很难找到的建议!以上是关于具有 API 网关和微服务的 Blazor 服务器指南的主要内容,如果未能解决你的问题,请参考以下文章