博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[WCF]设置拦截器捕捉到request和reply消息
阅读量:6218 次
发布时间:2019-06-21

本文共 7686 字,大约阅读时间需要 25 分钟。

在熟练掌握了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         ///  7         /// 加 8         ///  9         [OperationContract]10         Complex Add(Complex a, Complex b);11 12         /// 13         /// 减14         /// 15         [OperationContract]16         Complex Subtract(Complex a, Complex b);17 18         /// 19         /// 乘20         /// 21         [OperationContract]22         Complex Multiply(Complex a, Complex b);23 24         /// 25         /// 取模26         /// 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         ///  7         /// 实数 8         ///  9         [DataMember]10         public double A { get; set; }11 12         /// 13         /// 虚数14         /// 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.B11             };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.B20             };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.A29             };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 
2
3
4
5
6
7
8
9 10
11
12
13
14
15
16
17
18
19
20
21 22

然后服务端的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 += delegate10                 {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 
2
3
4
5

Main方法

1 namespace Cookiezhi.WcfStudy.Client 2 { 3     class Program 4     { 5         static void Main(string[] args) 6         { 7             using(ChannelFactory
factory = new ChannelFactory
("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 
2
3 4
5
6
7
8
9
10 11
12
13
14
15
16
17
18
19
20
21
22
23 24
25
26
27
28
29
30
31
32
33
34
35 36
37 38
39
40
41

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

然后我们尝试一下

 

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

 

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

转载地址:http://dioja.baihongyu.com/

你可能感兴趣的文章
好文推荐
查看>>
CSS3秘笈复习:第七章
查看>>
springboot~WebTestClient的使用
查看>>
docker~大叔对术语的解释
查看>>
setValue:forKey of nsobject
查看>>
[oracle实验]跨平台传输表空间 win -> linux
查看>>
快速掌握 Android Studio 中 Gradle 的使用方法 [转http://blog.csdn.net/feelang/article/details/41783317]...
查看>>
装饰器模式 decorator
查看>>
仿iReader切换皮肤进度条
查看>>
MD5
查看>>
javascript总结02
查看>>
利用WMITool解决浏览器快捷方式启动参数被篡改以及浏览器主页被劫持的问题
查看>>
swoole帮助文档
查看>>
第六周背单词软件测试与评估
查看>>
最后的笔记系列1/5
查看>>
三分 Error Curves
查看>>
UVA 1252 十五 Twenty Questions
查看>>
分布式架构
查看>>
as3 object与dictionary区别
查看>>
第 7 章 多主机管理 - 046 - 创建 Machine
查看>>