WCF には NetTcpContextBinding や WsHttpContextBinding といった、コンテキスト付バインディグが提供されています。コンテキスト付バインディングを使えば、クライアントからサービスに、任意のメタ情報を送信できます。
ただし、コンテキストとして指定できるのは文字列だけなので、使い勝手が悪いです。
そこで、先日紹介した「DataContractSerializer を使ってシリアル化・逆シリアル化を行うサンプル」の出番。
この方法を利用すれば、コンテキストに任意のオブジェクトを設定できそう。
using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Channels; using System.Text; using System.Xml; namespace SerializeSample { class Program { [DataContract] public class Person { [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } } [ServiceContract] public interface IGreetingService { [OperationContract] string Greet(); } public class GreetingService : IGreetingService { public string Greet() { // コンテキストから Person を取り出す Person p = GetContext<Person>("Person"); return string.Format("Hello, {0}!", p.Name); } } // コンテキストにオブジェクトを追加 public static void SetContext<T>(IClientChannel channel, string key, T obj) { IContextManager manager = channel.GetProperty<IContextManager>(); IDictionary<string, string> context = manager.GetContext(); context.Add(key, Serialize(obj)); manager.SetContext(context); } // コンテキストからオブジェクトを取り出す public static T GetContext<T>(string key) { ContextMessageProperty properties = (ContextMessageProperty)OperationContext.Current .IncomingMessageProperties[ContextMessageProperty.Name]; return Deserialize<T>(properties.Context[key]); } // DataContractSerializer を使ってシリアル化 public static string Serialize<T>(T obj) { StringBuilder buffer = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(buffer)) { DataContractSerializer serializer = new DataContractSerializer(typeof(T)); serializer.WriteObject(writer, obj); } return buffer.ToString(); } // DataContractSerializer を使って逆シリアル化 public static T Deserialize<T>(string s) { using (StringReader text = new StringReader(s)) using (XmlReader reader = XmlReader.Create(text)) { DataContractSerializer serializer = new DataContractSerializer(typeof(T)); return (T)serializer.ReadObject(reader); } } static void Main(string[] args) { // サービス起動 string address = "net.tcp://localhost:8080/Greeting"; ServiceHost host = new ServiceHost(typeof(GreetingService)); host.AddServiceEndpoint(typeof(IGreetingService), new NetTcpContextBinding(), address); host.Open(); // サービスを呼び出すためのチャネル生成 IGreetingService proxy = ChannelFactory<IGreetingService>.CreateChannel( new NetTcpContextBinding(), new EndpointAddress(address)); // コンテキストをセット Person p = new Person() { Name = "Ichiro", Age = 35 }; SetContext((IClientChannel)proxy, "Person", p); // サービス呼び出し。 // サービス側では、コンテキストから Person を取り出す。 string result = proxy.Greet(); // 結果を出力 Console.WriteLine(result); Console.ReadLine(); } } }
結構いいんじゃない?