WCF 的一切都是围绕着 Message 进行,那么 Message 究竟是什么样子?
[ServiceContract]
public interface ICalculate { [OperationContract] double Add(double a, double b); } public class CalculateService : ICalculate { public double Add(double a, double b) { Message msg = OperationContext.Current.RequestContext.RequestMessage; Console.WriteLine(msg); return a + b; } } public class WcfTest { public static void Test() { AppDomain.CreateDomain("Server").DoCallBack(delegate { ServiceHost host = new ServiceHost(typeof(CalculateService)); host.AddServiceEndpoint(typeof(ICalculate), new BasicHttpBinding(), "http://localhost:8080/calc"); host.Open(); }); ChannelFactory<ICalculate> factory = new ChannelFactory<ICalculate>(new BasicHttpBinding(), "http://localhost:8080/calc"); ICalculate o = factory.CreateChannel(); Console.WriteLine(o.Add(1, 2)); } } 输出 <s:Envelope xmlns:s="http://schemas./soap/envelope/">
<s:Header> <To s:mustUnderstand="1" xmlns="http://...">http://localhost:8080/calc</To> <Action s:mustUnderstand="1" xmlns="http://...">http:///ICalculate/Add</Action> </s:Header> <s:Body> <Add xmlns="http:///"> <a>1</a> <b>2</b> </Add> </s:Body> </s:Envelope> 事实上我们可以直接基于 Message Layer 进行编程,利用 OperationContract.Action 捕获特定 Action 的消息。 [ServiceContract]
public interface ICalculate { [OperationContract(Action = "Add", ReplyAction="Add")] Message ProcessMessage(Message m); } public class CalculateService : ICalculate { public Message ProcessMessage(Message m) { Data d = m.GetBody<Data>(); Console.WriteLine(d.I); return Message.CreateMessage(MessageVersion.Soap11, "Add", new Data(9999)); } } [DataContract] public class Data { [DataMember] public int I; public Data(int i) { this.I = i; } } public class WcfTest { public static void Test() { AppDomain.CreateDomain("Server").DoCallBack(delegate { ServiceHost host = new ServiceHost(typeof(CalculateService)); host.AddServiceEndpoint(typeof(ICalculate), new BasicHttpBinding(), "http://localhost:8080/calc"); host.Open(); }); ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>( new BasicHttpBinding(), "http://localhost:8080/calc"); IRequestChannel channel = factory.CreateChannel(); channel.Open(); Message request = Message.CreateMessage(MessageVersion.Soap11, "Add", new Data(1234)); Message reply = channel.Request(request); Console.WriteLine("-------------------"); Console.WriteLine(reply); channel.Close(); factory.Close(); } } 输出: 1234
------------------- <s:Envelope xmlns:s="http://schemas./soap/envelope/"> <s:Header /> <s:Body> <Data xmlns="http://..." xmlns:i="http://..."> <I>9999</I> </Data> </s:Body> </s:Envelope> 正如上面所看到的,所有的调用都被转换成消息后发送。这也符合 SOA 的规范,完全隔离,清晰的边界。(调用 "m.GetBody<Data>()" 后,会导致 Message.State 变更,再次访问会出错,有关详细信息请参考 MSDN 文档。) 我们还可以使用 MessageContractAttribute / MessageHeaderAttribute 来控制消息格式,这比 DataContractAttribute 要更加灵活。我们可以设置消息标头、消息体,包括是否对其中某些进行签名和加密处理。 [ServiceContract]
public interface ICalculate { [OperationContract] void Add(Data d); } public class CalculateService : ICalculate { public void Add(Data d) { Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage); Console.WriteLine("----------------"); Console.WriteLine("{0}/{1}", d.a, d.b); } } [MessageContract] public class Data { [MessageHeader] public double a = 1; [MessageBodyMember] public double b = 2; } public class WcfTest { public static void Test() { AppDomain.CreateDomain("Server").DoCallBack(delegate { ServiceHost host = new ServiceHost(typeof(CalculateService)); host.AddServiceEndpoint(typeof(ICalculate), new BasicHttpBinding(), "http://localhost:8080/calc"); host.Open(); }); ChannelFactory<ICalculate> factory = new ChannelFactory<ICalculate>(new BasicHttpBinding(), "http://localhost:8080/calc"); ICalculate o = factory.CreateChannel(); Data d = new Data(); d.a = 1234; d.b = 5678; o.Add(d); } } 输出: <s:Envelope xmlns:s="http://schemas./soap/envelope/">
<s:Header> <h:a xmlns:h="http:///">1</h:a> <To s:mustUnderstand="1" xmlns="http://s...">http://localhost:8080/calc</To> <Action s:mustUnderstand="1" xmlns="http://...">http:///ICalculate/Add</Action> </s:Header> <s:Body> <Data xmlns="http:///"> <b>2</b> </Data> </s:Body> </s:Envelope> ---------------- 1234/5678 有关 Message 更详细的信息,可以参考 MSDN (Microsoft Windows SDK) 文档。 |
|