今まではクライアントの情報をサービスに引数で渡してました
プロジェクト ID やクライアント ID といったクライアントの情報を、サービスに引数として渡していました。でもこの方法は全然洗練されていません。引数が増えてしまう。できればクライアント情報を渡す部分は隠ぺいしたい。
コンテキスト付きバインディングを使えば引数で渡さなくていい!
.NET Framework 3.5 で追加されたコンテキスト付きバインディングを使えば、任意のクライアントの情報をメッセージのヘッダに埋め込むことができます。引数で渡す必要が無くなる!
コンテキスト付きバインディングには、BasicHttpContextBinding, NetTcpContextBinding, WSHttpContextBinding があります。これらは System.Workflow.Services.dll アセンブリに含まれています。
クライアント側はIContextManagerを使ってコンテキストを渡す
ISampleService proxy = ChannelFactory<ISampleService>.CreateChannel( new NetTcpContextBinding(), new EndpointAddress("net.tcp://localhost:8000/SampleService")); IContextManager manager = ((IChannel)proxy).GetProperty<IContextManager>(); IDictionary<string, string> context = manager.GetContext(); context["ProjectId"] = "12345"; context["ClientId"] = "sample"; manager.SetContext(context); proxy.Execute();
ここで1つ注意点。コンテキストはプロキシを開く(またはそれを初めて使用する)前に1回だけ設定できます。その後は辞書がキャッシュされ、それを変更しようとするとエラーになります。
サービス側はContextMessagePropertyを使ってコンテキストを取り出す
public void Execute() { ContextMessageProperty props = OperationContext.Current.IncomingMessageProperties[ContextMessageProperty.Name] as ContextMessageProperty; string projectId = props.Context["ProjectId"]; string clientId = props.Context["ClientId"]; Console.WriteLine("ProjectId:{0}, ClientId:{1}", projectId, clientId); }
これで明示的に渡したくない情報を裏でこっそり渡せます
クライアント情報を引数で渡す必要が無くなるので、サービスコントラクトがスッキリしそうです。
実用を考えると、IChannel をラップするクラスを作って、IContextManager を使って情報を設定する部分を隠ぺいした方が良いでしょうね。
サービス側でコンテキストを取り出すためのヘルパーを作るとなお良いです。