码迷,mamicode.com
首页 > 其他好文 > 详细

[WCF]设置拦截器捕捉到request和reply消息

时间:2015-10-29 23:26:05      阅读:439      评论:0      收藏:0      [点我收藏+]

标签:

WCF进阶学习ing...

在熟练掌握了ABC的使用以后,就开始想着去了解WCF是怎么通信的了。首先是服务描述语言wsdl,它定义了服务的描述等等,用于让外界知道这个服务的ABC是什么。另外一个比较重要的就是消息。

WCF是通过消息进行通讯的,一般是使用SOAP形式。服务端的信道监听器接收到消息之后,对消息进行反序列化,解码,然后通过激活对象,再去invoke相应的操作,操作的结果(返回值)再通过编码,序列化,传送给调用者,调用者再对消息进行反序列化,解码,最后拿到结果。所以在这个过程中,对消息的理解和熟悉对于我们理解WCF的操作流程是很大的帮助的。

然后我们就开始拦截这个消息来看看这个消息到底是什么。。。废话不多说,上code。。

首先创建一个提供复数计算的服务,使用共享C的方式,项目结构如下,服务端和客户端都是一个控制台程序

技术分享

 

服务契约代码 IComplexCalculate.cs:

 1 namespace Cookiezhi.WcfStudy.Contracts.ServiceContracts
 2 {
 3     [ServiceContract(Namespace="http://www.cookiezhi.com/service/complex")]
 4     public interface IComplexCalculate
 5     {
 6         /// <summary>
 7         /// 8         /// </summary>
 9         [OperationContract]
10         Complex Add(Complex a, Complex b);
11 
12         /// <summary>
13         ///14         /// </summary>
15         [OperationContract]
16         Complex Subtract(Complex a, Complex b);
17 
18         /// <summary>
19         ///20         /// </summary>
21         [OperationContract]
22         Complex Multiply(Complex a, Complex b);
23 
24         /// <summary>
25         /// 取模
26         /// </summary>
27         [OperationContract]
28         double Modulus(Complex a);
29     }
30 }

数据契约 Complex.cs:

 1 namespace Cookiezhi.WcfStudy.Contracts.DataContracts
 2 {
 3     [DataContract(Namespace = "http://www.cookiezhi.com/data/complex")]
 4     public class Complex
 5     {
 6         /// <summary>
 7         /// 实数
 8         /// </summary>
 9         [DataMember]
10         public double A { get; set; }
11 
12         /// <summary>
13         /// 虚数
14         /// </summary>
15         [DataMember]
16         public double B { get; set; }
17     }
18 }

服务契约实现 ComplexCalculateService:

 1 namespace Cookiezhi.WcfStudy.Services
 2 {
 3     public class ComplexCalculateService : IComplexCalculate
 4     {
 5         public Complex Add(Complex a, Complex b)
 6         {
 7             return new Complex()
 8             {
 9                 A = a.A + b.A,
10                 B = a.B + b.B
11             };
12         }
13 
14         public Complex Subtract(Complex a, Complex b)
15         {
16             return new Complex()
17             {
18                 A = a.A - b.A,
19                 B = a.B - b.B
20             };
21         }
22 
23         public Complex Multiply(Complex a, Complex b)
24         {
25             return new Complex()
26             {
27                 A = a.A * b.A - a.B * b.B,
28                 B = a.A * b.B + a.B * b.A
29             };
30         }
31 
32         public double Modulus(Complex a)
33         {
34             return Math.Sqrt(a.A * a.A + a.B * a.B);
35         }
36     }
37 }

采用配置文件方式去设置服务 app.config:

 1 <system.serviceModel>
 2     <behaviors>
 3       <serviceBehaviors>
 4         <behavior name="mexBehavior">
 5           <serviceMetadata httpGetEnabled="true"/>
 6         </behavior>
 7       </serviceBehaviors>
 8     </behaviors>
 9     
10     <services>
11       <service name="Cookiezhi.WcfStudy.Services.ComplexCalculateService" behaviorConfiguration="mexBehavior">
12         <endpoint address="" binding="basicHttpBinding" contract="Cookiezhi.WcfStudy.Contracts.ServiceContracts.IComplexCalculate" />
13         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
14         <host>
15           <baseAddresses>
16             <add baseAddress="http://127.0.0.1:9999/complexcalcservice"/>
17           </baseAddresses>
18         </host>
19       </service>
20     </services>
21     
22   </system.serviceModel>

然后服务端的main方法里启动服务:

 1 namespace Cookiezhi.WcfStudy.Hosting
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             using(ServiceHost host = new ServiceHost(typeof(ComplexCalculateService)))
 8             {
 9                 host.Opened += delegate
10                 {
11                     Console.WriteLine("Service {0} started", host.Description.Name);
12                 };
13 
14                 host.Open();
15 
16                 Console.ReadKey();
17             }
18         }
19     }
20 }

OK, 服务端好了,我们启动一下

技术分享

再看一下WSDL

技术分享

 

OK是好的,这些对于做过WCF相关的朋友们都是轻车熟路了,下面是客户端,通过配置文件加ChannelFactory方式来创建并调用

App.config

1 <system.serviceModel>
2     <client>
3       <endpoint name="ComplexCalculateService" address="http://127.0.0.1:9999/complexcalcservice" binding="basicHttpBinding" contract="Cookiezhi.WcfStudy.Contracts.ServiceContracts.IComplexCalculate" />
4     </client>
5   </system.serviceModel>

Main方法

 1 namespace Cookiezhi.WcfStudy.Client
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             using(ChannelFactory<IComplexCalculate> factory = new ChannelFactory<IComplexCalculate>("ComplexCalculateService"))
 8             {
 9                 IComplexCalculate proxy = factory.CreateChannel();
10 
11                 Complex a = new Complex() { A = 1, B = 2 };
12                 Complex b = new Complex() { A = 2, B = 1 };
13                 Complex result = null;
14 
15                 result = proxy.Add(a, b);
16                 Console.WriteLine("Add result is {0} + {1}i", result.A, result.B);
17 
18                 Console.ReadKey();
19             }
20         }
21     }
22 }

调用服务:

技术分享

 

前戏做完了,我们开始进入主题:

我们需要拦截消息,并把消息打印出来,那么我们就需要一个拦截器,叫做MessageInspector,WCF为我们提供了两种拦截器:

客户端拦截器 IClientMessageInspector

提供两个接口

BeforeSendRequest:向服务器发送请求前执行

AfterReceiveReply:接收到服务器的回复消息后执行

服务端拦截器 IDispatchMessageInspector

他也提供两个接口

AfterReceiveRequest:invoke操作之前执行

BeforeSendReply:发送reply给客户端之前执行

 

在这里我们在服务端设置个拦截器,然后打印出请求和回复的消息,所以我们使用IDispatchMessageInspector这个接口

实现接口 MessageInspector.cs

 1 namespace Cookiezhi.WcfStudy.Hosting.MessageInspect
 2 {
 3     public class MessageInspector : IDispatchMessageInspector
 4     {
 5         public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
 6         {
 7             Console.WriteLine(request.ToString());
 8             return DateTime.Now;
 9         }
10 
11         public void BeforeSendReply(ref Message reply, object correlationState)
12         {
13             Console.WriteLine(reply.ToString());
14             DateTime requestTime = (DateTime)correlationState;
15 
16             var duration = DateTime.Now - requestTime;
17             Console.WriteLine(duration);
18         }
19     }
20 }

其中AfterReceiveRequest先执行,然后去执行远程方法,然后再执行BeforeSendReply,所以在这里加了一个操作计时的功能(可选)。

然后我们要将这个拦截器给寄宿在我们的终结点上,所以需要定义一个终结点行为(EndpointBehavior),并寄宿在服务上。

MessageInspectorBehavior.cs,在ApplyDispatchBehavior方法实现中将我们新建的Inspector实例加到dispatcher的MessageInspectors中

 1 namespace Cookiezhi.WcfStudy.Hosting.MessageInspect
 2 {
 3     public class MessageInspectorBehavior : IEndpointBehavior
 4     {
 5         public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
 6         {
 7         }
 8 
 9         public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
10         {
11         }
12 
13         public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
14         {
15             endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MessageInspector());16         }
17 
18         public void Validate(ServiceEndpoint endpoint)
19         {
20         }
21     }
22 }

最后创建一个配置元素用于在配置文件中给终结点配置这个行为.

 1 namespace Cookiezhi.WcfStudy.Hosting.MessageInspect
 2 {
 3     public class MessageInspectorExtensionElement : BehaviorExtensionElement
 4     {
 5         public override Type BehaviorType
 6         {
 7             get { return typeof(MessageInspectorBehavior); }
 8         }
 9 
10         protected override object CreateBehavior()
11         {
12             return new MessageInspectorBehavior();
13         }
14     }
15 }

下面就是配置这个行为了

App.config

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3 
 4   <system.serviceModel>
 5     <extensions>
 6       <behaviorExtensions>
 7         <add name="messageInspector" type="Cookiezhi.WcfStudy.Hosting.MessageInspect.MessageInspectorExtensionElement, Cookiezhi.WcfStudy.Hosting"/>
 8       </behaviorExtensions>
 9     </extensions>
10     
11     <behaviors>
12       <serviceBehaviors>
13         <behavior name="mexBehavior">
14           <serviceMetadata httpGetEnabled="true"/>
15         </behavior>
16       </serviceBehaviors>
17       <endpointBehaviors>
18         <behavior name="messageInspector">
19           <messageInspector />
20         </behavior>
21       </endpointBehaviors>
22     </behaviors>
23     
24     <services>
25       <service name="Cookiezhi.WcfStudy.Services.ComplexCalculateService" behaviorConfiguration="mexBehavior">
26         <endpoint address="" binding="basicHttpBinding" contract="Cookiezhi.WcfStudy.Contracts.ServiceContracts.IComplexCalculate" behaviorConfiguration="messageInspector" />
27         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
28         <host>
29           <baseAddresses>
30             <add baseAddress="http://127.0.0.1:9999/complexcalcservice"/>
31           </baseAddresses>
32         </host>
33       </service>
34     </services>
35     
36   </system.serviceModel>
37   
38     <startup> 
39         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
40     </startup>
41 </configuration>

客户端的代码不要做出任何的改变,

然后我们尝试一下

技术分享

 

Great! 我们成功的拦截了请求,并将请求信息打印了出来。

 

总结,有了这个拦截器,我们可以做很多的事情,比如修改消息头和消息体,计算消息的大小(流量统计),统计服务调用的次数和平均时间,客户端情况,等等。

[WCF]设置拦截器捕捉到request和reply消息

标签:

原文地址:http://www.cnblogs.com/cookiezhi/p/4922027.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!