ASP.NET SignalRの高度な機能:特集:ASP.NET SignalR入門(後編)(2/3 ページ)
SignalRを利用して、特定のクライアントのみへの通知やユーザーの認証といった機能を実装するには? 実践的なアプリ開発に必須ともいえる機能を紹介する。
ユーザーの認証
SignalRはASP.NETの上に構築されているので、特に専用の認証方法が用意されているわけでもなく、Windows認証やフォーム認証などを特に意識することなく使うことができる。
そして実際にSignalRのハブ・メソッドに認証をかける場合には、ASP.NET MVCやWeb APIと同じくAuthorize属性をメソッドに指定するだけだ。
public class AuthorizeHub : Hub
{
// Method1はログイン済みユーザーしか呼び出せない
[Authorize]
public string Method1()
{
return "ok";
}
// Method2は誰でも呼び出し可能
public string Method2()
{
return "ok";
}
}
ほとんどの場合はこれで十分だと思うが、SignalRではほかのクライアントからブロードキャストされたメッセージに対して認証をかけることが可能だ。ブロードキャストされたメッセージに対して認証をかけるには、ハブ・クラスにAuthorize属性を指定し、さらにその属性のRequireOutgoingプロパティにtrueをセットすればいい。
// サーバからクライアントへ送信されるメッセージに認証をかける
[Authorize(RequireOutgoing = true)]
public class AuthorizeHub : Hub
{
public void Method1()
{
Clients.All.Notify("ok");
}
}
この場合では、ハブのメソッドは自由に呼び出し可能だが、Notifyメッセージが送信されるのは認証済みのクライアントだけとなる。Authorize属性ではロール・ベースで制限することも可能なので、組み合わせることで面白い機能を実装できるだろう。
HubPipeline
前回でも少しだけ触れたが、SignalRのバージョン1.0からは「HubPipeline」と呼ばれる仕組みが追加された。このHubPipelineを利用することで、ASP.NET MVCのアクション・フィルタのようにメソッドが実行される前、実行された後などで独自の処理を行えるようになった。
HubPipelineの実体はIHubPipelineModuleインターフェイスを実装したクラスの集合となっている。IHubPipelineModuleインターフェイスで定義されているメソッドはプリミティブなものが多く、簡単に扱えるようなものではないため、実際に使用する場合には基本的な部分が実装済みのHubPipelineModuleクラスを継承するのが簡単だ。HubPipelineModuleクラスにはASP.NET MVCのアクション・フィルタに似たメソッドが用意されているので、必要なメソッドだけオーバーライドすればいい。
ここではHubPipelineを利用して、全てのSignalRリクエストのログを出力するモジュールを紹介する。
using Microsoft.AspNet.SignalR.Hubs;
using System.Diagnostics;
public class LoggingHubModule : HubPipelineModule
{
protected override bool OnBeforeConnect(IHub hub)
{
Debug.WriteLine("OnBeforeConnect: {0}", (object)hub.Context.ConnectionId);
return true;
}
protected override void OnAfterConnect(IHub hub)
{
Debug.WriteLine("OnAfterConnect: {0}", (object)hub.Context.ConnectionId);
}
protected override bool OnBeforeIncoming(IHubIncomingInvokerContext context)
{
Debug.WriteLine("OnBeforeIncoming: {0}, {1}", context.Hub.Context.ConnectionId, context.MethodDescriptor.Name);
return true;
}
protected override object OnAfterIncoming(object result, IHubIncomingInvokerContext context)
{
Debug.WriteLine("OnAfterIncoming: {0}, {1}, {2}", context.Hub.Context.ConnectionId, context.MethodDescriptor.Name, result);
return result;
}
protected override bool OnBeforeOutgoing(IHubOutgoingInvokerContext context)
{
Debug.WriteLine("OnBeforeOutgoing: {0}", (object)context.Invocation.Method);
return true;
}
protected override void OnAfterOutgoing(IHubOutgoingInvokerContext context)
{
Debug.WriteLine("OnAfterOutgoing: {0}", (object)context.Invocation.Method);
}
protected override bool OnBeforeDisconnect(IHub hub)
{
Debug.WriteLine("OnBeforeDisconnect: {0}", (object)hub.Context.ConnectionId);
return true;
}
protected override void OnAfterDisconnect(IHub hub)
{
Debug.WriteLine("OnAfterDisconnect: {0}", (object)hub.Context.ConnectionId);
}
protected override bool OnBeforeReconnect(IHub hub)
{
Debug.WriteLine("OnBeforeReconnect: {0}", (object)hub.Context.ConnectionId);
return true;
}
protected override void OnAfterReconnect(IHub hub)
{
Debug.WriteLine("OnAfterReconnect: {0}", (object)hub.Context.ConnectionId);
}
}
HubPipelineModuleクラスには“Before”と“After”という対になったメソッドが用意されている。そして「Before」と名の付くメソッドは戻り値としてfalseを返すことで、その後の処理を中断してリクエストを終了させられるのが特徴だ。
それぞれのメソッドの引数からは、呼び出されたハブやメソッドの情報が取得可能なのでロギング以外にも使える場面は多いだろう。
そして作成したモジュールはアプリの開始時にGlobalHost.HubPipelineプロパティで得られるオブジェクトのAddModuleメソッドを呼び出して登録する。これで実際にモジュールの各メソッドが実行される。
protected void Application_Start(object sender, EventArgs e)
{
// 作成したLoggingHubModuleを追加する
GlobalHost.HubPipeline.AddModule(new LoggingHubModule());
RouteTable.Routes.MapHubs();
}
実際にモジュールを登録してクライアントからの接続、メソッド呼び出し、切断といった処理を行ったときの出力は以下のとおりだ。
ログを出力することで、SignalRが内部でどの順番でリクエストを処理し、さらにクライアントへメッセージを通知しているかを理解できるだろう。
Copyright© Digital Advantage Corp. All Rights Reserved.