到目前为止,我还没有找到关于使用带有API网关和微服务的Blazor服务器(而非WebAssembly(的指导。讨论这些Blazor与API网关和微服务的文章总是提到Blazor WebAssembly(Wasm(。(是否假设Blazor Server应用程序不会使用微服务?此外,就其价值而言,选择Blazor服务器而不是Blazor WebAssembly的原因是为了更好地保护知识产权。(
无论如何我想知道的是Blazor服务器应用程序是否应该位于网关前面,通过网关将其内部API调用发送到网关后面的微服务,比如…
[浏览器]----(SignalR(----[Blaczor服务器应用程序]----(https(----[API网关]----(http(----[微服务]
或者把应用程序放在网关后面,让SignalR连接隧道通过网关,像这样更有意义吗…
【浏览器】----(SignalR(----【API网关】----(SignalR(-----【Blazor服务器应用程序】----(http(----【微服务】
在建立SignalR连接之前,请记住浏览器中应用程序的初始加载。这需要单独处理吗?它是否影响上述选项的选择?我缺少更好的解决方案吗?
我们使用Blazor服务器端作为Azure Service Fabric(本身是一个无状态的ASP.NET核心服务(中运行的微服务集合的前端,因此这是一个完全合法的场景。我们的整个应用程序在Azure的云中运行,所以我将使用它的产品来描述我们的实现。
为了更好地分离关注点并更容易地确保互联网边界,我们为公共API和SignalR提供了两个单独的服务。因此,API网关充当了一个安全边界,因为它可以处理HTTPS卸载,位于公共面向子网上,并路由到虚拟网络上的内部服务。然后,提供SignalR访问的服务在应用网关实例后面的面向公共的子网上运行(用于防火墙+服务路由功能(。
因此,我们有两个服务设置如下:
SignalR服务
[浏览器]--(SignalR(--[Azure应用程序网关]--[Azure服务结构-Blazor服务器端应用程序]--[SF服务远程处理]--[微服务]
API服务
[浏览器]--(https(--[Azure API管理]--(http(--[Microsoft Service Fabric-ASP.NET Core API]--[SF Service Remoting]--[微服务]
Microservice Gotcha-数据保护
特别是在支持身份验证时,ASP.NET Core会在内部设置一些密钥,用于加密Blazor会话中使用的状态。在微服务场景中,除非你在网络堆栈(负载平衡器、网关、路由器等(中一直使用粘性路由,以确保所有请求都能到达同一个实例(而且可能你的实例在你不注意的时候没有重建和移动到其他地方(,否则你会遇到关于无法解除状态保护的模糊且无益的错误。
修复非常简单——在ASP.NET Core服务的Startup.cs中,确保设置了services.AddDataProtection();
并进行了适当的配置。由于我们使用的是Service Fabric,因此我们使用的第三方库可以很好地用于此目的。要使用,请将NuGet包SoCreate.AspNetCore.DatapProtection.ServiceFabric
安装到ASP.NET Core服务中,然后在ConfigureServices()
方法中的Startup.cs中简单地放置以下内容:
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))
{
}
}
}
您可以在";网络农场";或者这里的微服务/分布式环境。