WCF学习笔记(2)---消息交换模式
WCF是基于消息的开发框架。其中,消息交换的模式一共有三种,分别为:数据报、请求/应答和双工。
数据报交换模式: 用于单向的消息发送。即发即弃。
请求/应答交换模式: 也叫半双工。一方请求,另一方应答。 类似于对讲机。
双工交换模式: 也叫全双工,发送者和接收者可以互发消息。类似于电话。
示例代码:
契约:
1 [ServiceContract(CallbackContract = typeof(IExampleCallbackClass))]
2 public interface IExampleClass
3 {
4 [OperationContract(IsOneWay = true)]
5 void SendMessage(string message);
6
7 [OperationContract()]
8 string RequestMessage();
9
10 [OperationContract(IsOneWay = true)]
11 void SendMessageAgain(string message);
12 }
13
14 public interface IExampleCallbackClass
15 {
16 [OperationContract(IsOneWay= true)]
17 void CallBack(string message);
18 } 2 public interface IExampleClass
3 {
4 [OperationContract(IsOneWay = true)]
5 void SendMessage(string message);
6
7 [OperationContract()]
8 string RequestMessage();
9
10 [OperationContract(IsOneWay = true)]
11 void SendMessageAgain(string message);
12 }
13
14 public interface IExampleCallbackClass
15 {
16 [OperationContract(IsOneWay= true)]
17 void CallBack(string message);
实现:
1 [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
2 public class ExampleClass : IExampleClass
3 {
4 public void SendMessage(string message)
5 {
6 Console.WriteLine("Send Message: " + message);
7 }
8 public string RequestMessage()
9 {
10 return "Request and Response!";
11 }
12 public void SendMessageAgain(string message)
13 {
14 Console.WriteLine("Send message again: " + message);
15 var callBack = OperationContext.Current.GetCallbackChannel<IExampleCallbackClass>();
16 callBack.CallBack("Send Callback: " + message);
17 }
18 }
19
20 public class ExampleCallbackClass : IExampleCallbackClass
21 {
22 public void CallBack(string message)
23 {
24 Console.WriteLine("Print Callback :" + message);
25 }
26 }
2 public class ExampleClass : IExampleClass
3 {
4 public void SendMessage(string message)
5 {
6 Console.WriteLine("Send Message: " + message);
7 }
8 public string RequestMessage()
9 {
10 return "Request and Response!";
11 }
12 public void SendMessageAgain(string message)
13 {
14 Console.WriteLine("Send message again: " + message);
15 var callBack = OperationContext.Current.GetCallbackChannel<IExampleCallbackClass>();
16 callBack.CallBack("Send Callback: " + message);
17 }
18 }
19
20 public class ExampleCallbackClass : IExampleCallbackClass
21 {
22 public void CallBack(string message)
23 {
24 Console.WriteLine("Print Callback :" + message);
25 }
调用:
1 static void Main(string[] args)
2 {
3 // 启动服务
4 WSDualHttpBinding dualBinding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
5 dualBinding.MessageEncoding = WSMessageEncoding.Text;
6
7 Uri address = new Uri("http://localhost:8000/Datapram", UriKind.Absolute);
8 ServiceHost svc = new ServiceHost(typeof(ExampleClass));
9 svc.AddServiceEndpoint(typeof(IExampleClass), dualBinding, address);
10 svc.Open();
11
12 Console.WriteLine("WCF服务已经启动!");
13
14 // 调用服务
15 WSDualHttpBinding remoteBinding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
16 EndpointAddress remoteAddress = new EndpointAddress(
17 new Uri("http://localhost:8000/Datapram", UriKind.Absolute));
18
19 IExampleCallbackClass callBack = new ExampleCallbackClass();
20 IExampleClass proxy = DuplexChannelFactory<IExampleClass>.CreateChannel(callBack, remoteBinding, remoteAddress);
21
22 //数据报交换模式
23 proxy.SendMessage("some message");
24
25 // 请求应答模式
26 string responseString = proxy.RequestMessage();
27 Console.WriteLine("收到服务器的应答:" + responseString);
28
29 // 双工
30 proxy.SendMessageAgain("message");
31
32 Console.WriteLine("服务调用成功!");
33 Console.ReadLine();
34 }
35 }
2 {
3 // 启动服务
4 WSDualHttpBinding dualBinding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
5 dualBinding.MessageEncoding = WSMessageEncoding.Text;
6
7 Uri address = new Uri("http://localhost:8000/Datapram", UriKind.Absolute);
8 ServiceHost svc = new ServiceHost(typeof(ExampleClass));
9 svc.AddServiceEndpoint(typeof(IExampleClass), dualBinding, address);
10 svc.Open();
11
12 Console.WriteLine("WCF服务已经启动!");
13
14 // 调用服务
15 WSDualHttpBinding remoteBinding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
16 EndpointAddress remoteAddress = new EndpointAddress(
17 new Uri("http://localhost:8000/Datapram", UriKind.Absolute));
18
19 IExampleCallbackClass callBack = new ExampleCallbackClass();
20 IExampleClass proxy = DuplexChannelFactory<IExampleClass>.CreateChannel(callBack, remoteBinding, remoteAddress);
21
22 //数据报交换模式
23 proxy.SendMessage("some message");
24
25 // 请求应答模式
26 string responseString = proxy.RequestMessage();
27 Console.WriteLine("收到服务器的应答:" + responseString);
28
29 // 双工
30 proxy.SendMessageAgain("message");
31
32 Console.WriteLine("服务调用成功!");
33 Console.ReadLine();
34 }
35 }
数据报和请求/调用的绑定,可以使用 WSHttpBinding 来做,因为,三种方式都写入到一个示例里,所以用了 WSDualHttpBinding。
需要注意的部分:在IExampleClass 的实现中,需要声明特性:[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)].如果不声明,运时的时候会报"操作将死锁..."的异常。出现这个异常的原因是:在默认的情况下,服务的执行按Single并发模式进行,也就是说在服务执行全程,服务对象只能被一个线程访问。WCF通过加锁机制保证服务对象的独占性使用,也就是说在服务执行开始会对服务对象加锁,该锁在服务操作结束之后释放。