SignalR は、Azure Web ロールを使用して驚くほどスケーリングします。ただし、Azure ワーカー ロール内でセルフホステッド OWIN プロジェクトを使用すると、複数のインスタンスが追加されると SignalR で問題が発生し始めます。記録として、私のプロジェクトではバックプレーンに Redis を使用しています。
Azure ワーカー ロール インスタンスを 1 を超える数に増やすと、クライアント接続がランダムに失敗し、"ConnectionId の形式が正しくありません" というエラーが表示されます。これは、負荷分散のために単一のクライアントのネゴシエーションが複数のサーバーにまたがる場合に発生すると考えられます。ネゴシエーションに参加している複数のサーバーがデータを解読できるとは思えません (DPAPI が隠蔽されていますか?)。
app.config で < machineKey /> validationKey と decryptionKey を設定しようとしましたが、違いはないようです。問題は残ります。この場合も、プロジェクトは Web ロール (IIS) として正常に機能しますが、ワーカー ロール (OWIN セルフホスト) としては機能しません。
これが DpapiDataProtectionProvider の問題であると仮定すると、プロバイダーが複数のサーバー/インスタンスで同じ暗号化/復号化の結果をレンダリングするようにするにはどうすればよいですか?
解決
SignalR (DpapiDataProtectionProvider) によって使用される既定の保護プロバイダーは、Azure ワーカー ロールのスケールアウトをサポートしていないようです。独自のサンプル プロバイダーを展開することで、SignalR/OWIN/Azure Worker をスケーリングし、ランダムな 400 HTTP/「接続 ID の形式が正しくありません」を受け取ることができませんでした。以下のサンプルは、トークンを保護/保護しないことに注意してください。
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("/");
}
}