読者です 読者をやめる 読者になる 読者になる

WCF でメッセージヘッダにデータを埋め込んでこっそりやり取りするメモ

WCF を使ったアプリにて

自前のセッション機能を実装してるんですが、それで使うセッション ID をクライアントとサービスの間でやりとりしたい。引数や戻り値ではなく、裏でこっそり渡すのがベターです。

そんなちょっとしたデータを、WCF のメッセージヘッダに埋め込んでやり取りできるか試してみました。

サンプルはこんな感じ

OperationContext の IncomingMessageHeaders と OutgoingMessageHeaders を使って、メッセージヘッダを操作します。

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace WcfMessageHeaderSample
{
    [ServiceContract]
    public interface IGreetingService
    {
        [OperationContract]
        void Greet();
    }

    public class GreetingService : IGreetingService
    {
        public void Greet()
        {
            // ヘッダに埋め込まれてクライアントから送られたデータ
            var name = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("Name", "Test");
            Console.WriteLine("Name:{0}", name);

            var result = string.Format("Hello,{0}.", name);

            // ヘッダに埋め込んでクライアントに返すデータ
            OperationContext.Current.OutgoingMessageHeaders.Add(
                MessageHeader.CreateHeader("Greet", "Test", result));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            const string address = "net.pipe://localhost/Greeting";
            var binding = new NetNamedPipeBinding();

            // サービス起動
            var host = new ServiceHost(typeof(GreetingService));
            host.AddServiceEndpoint(typeof(IGreetingService),
                binding,
                address);
            host.Open();

            // プロキシ作成
            var proxy = ChannelFactory<IGreetingService>.CreateChannel(
                binding,
                new EndpointAddress(address));

            // ヘッダを操作するときは OperationContextScope で囲む
            using (var scope = new OperationContextScope((IClientChannel)proxy))
            {
                // ヘッダに埋め込んでサービスに送るデータ
                OperationContext.Current.OutgoingMessageHeaders.Add(
                    MessageHeader.CreateHeader("Name", "Test", "Ichiro"));

                // サービス呼び出し
                proxy.Greet();

                // ヘッダに埋め込まれてサービスから返されたデータ
                var result = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("Greet", "Test");
                Console.WriteLine("Result:{0}", result);
            }

            Console.ReadLine();
            ((IClientChannel)proxy).Close();
            host.Close();
        }
    }
}

実行してみると

f:id:griefworker:20110223154026p:image
うまくいってますね。

あとは

ヘッダを操作している部分を、RealProxy や高階関数を使って AOP っぽく実装してやれば、ちょっとしたオレオレフレームワークが出来そう。