SignalR使用Azure Web角色实现了惊人的扩展。但是,当我在Azure角色中使用自托管的OWIN项目时,添加多个实例时SignalR将开始出现问题。作为记录,我的项目使用Redis作为背板。
将Azure Worker角色实例增加到一个以上时,客户端连接将随机失败,并显示错误 “ ConnectionId格式不正确” 。我认为这是由于负载平衡而导致单个客户端的协商跨越多个服务器时引起的;我不认为参与协商的多台服务器可以解密数据(掩盖下的DPAPI?)。
我尝试在app.config中设置 validationKey和decryptionKey,但这似乎没有什么不同。问题仍然存在。同样,该项目可以很好地用作Web角色(IIS),但不能作为辅助角色(OWIN自宿主)。
假设这是DpapiDataProtectionProvider的问题,如何确保该提供程序在多个服务器/实例之间呈现相同的加密/解密结果?
解
SignalR(DpapiDataProtectionProvider)使用的默认保护提供程序似乎不支持Azure Worker Role横向扩展。通过滚动自己的样本提供程序,我可以缩放SignalR / OWIN / Azure Worker,并且不会收到随机的400 HTTP /“ ConnectionId格式不正确”。请注意,以下示例不会保护/保护令牌。
public class ExampleDataProvider : IDataProtector { public byte[] Protect(byte[] userData) { Trace.TraceInformation("Protect called: " + Convert.ToBase64String(userData)); return userData; } public byte[] Unprotect(byte[] protectedData) { Trace.TraceInformation("Unprotect called: " + Convert.ToBase64String(protectedData)); return protectedData; } } public class ExampleProtectionProvider : IDataProtectionProvider { public IDataProtector Create(params string[] purposes) { Trace.TraceInformation("Example Protection Provider Created"); return new ExampleDataProvider(); } }
在Owin启动期间注入自定义提供程序:
public class Startup { public void Configuration(IAppBuilder app) { app.SetDataProtectionProvider(new ExampleProtectionProvider()); GlobalHost.DependencyResolver.UseRedis(new RedisScaleoutConfiguration("0.0.0.0", 0, "", "Example")); app.MapSignalR(new HubConfiguration { EnableDetailedErrors = true }); app.UseWelcomePage("/"); } }
如果SignalR不为null,则使用IAppBuilder.Properties [“ security.DataProtectionProvider”]中的IDataProtectionProvider。
在调用MapSignalR之前,可以在Startup.Configuration中用您自己的IDataProtectionProvider替换它。
通过提供您自己的IDataProtectionProvider,可以确保每个工作角色使用相同的密钥来保护/取消保护。