コンテキスト付きバインディングを使わずにWCFサービスにメタ情報を渡す方法

以前、WCF でクライアントからサービスにメタ情報を渡す方法として、コンテキスト付きバインディングを使う方法を紹介しました。

クライアントが Windows アプリケーションなら、この方法で良いんですが、Silverlight の場合使えません。Silverlight にはコンテキスト付きバインディングが無いんです。まぁ、コンテキスト付きバインディング自体、WF から拝借してきたものなので、以前から気持ち悪さを感じていたんですが…。

そもそも、コンテキスト付きバインディングなんか使わずに、直接メッセージヘッダにデータを突っ込めば良かったんです。こんな風に。

// チャネル作成
IFooService client = ChannelFactory<IFooService>.CreateChannel(
    new NetNamedPipeBinding(),
    new EndpointAddress("net.pipe://localhost/Foo"));

// ヘッダ操作は OperationContextScope 内で行う
using (OperationContextScope scope = new OperationContextScope((IClientChannel)client))
{
    // ヘッダに格納して送る情報
    User user = new User { Name = "ルフィ" };

    // ヘッダを追加
    MessageHeader header = MessageHeader.CreateHeader(
        "User",
        "UserHeader",
        user);
    OperationContext.Current.OutgoingMessageHeaders.Add(header);

    // サービス呼び出し
    client.Foo();
}

// チャネルを閉じる
((IClientChannel)client).Close();

サービス側では、こんな風にヘッダからデータを取り出せます。

public class FooService : IFooService
{
    public void Foo()
    {
        // ヘッダからデータを取り出す
        // name と namespace を指定する
        var user = OperationContext.Current.IncomingMessageHeaders
            .GetHeader<User>("User", "UserHeader");

        Console.WriteLine(user.Name);
    }
}

OperationContext には OutgoingMessageHeaders と IncommingMessageHeaders の2つのプロパティがあって、ちょっとややこしいです。私は次のように整理しています。

  • OutgoingMessageHeaders は、「出ていくメッセージ」のヘッダを操作するためのプロパティ。
    • メッセージを送る側が使う。
  • IncommingMessageHeaders は「入ってきたメッセージ」のヘッダを操作するためのプロパティ。
    • メッセージの受ける側が使う。

「そのまんま」とか言わないw。