WCF进阶学习ing...

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

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

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

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

服务契约代码 IComplexCalculate.cs:

 namespace Cookiezhi.WcfStudy.Contracts.ServiceContracts
{
[ServiceContract(Namespace="http://www.cookiezhi.com/service/complex")]
public interface IComplexCalculate
{
/// <summary>
/// 加
/// </summary>
[OperationContract]
Complex Add(Complex a, Complex b); /// <summary>
/// 减
/// </summary>
[OperationContract]
Complex Subtract(Complex a, Complex b); /// <summary>
/// 乘
/// </summary>
[OperationContract]
Complex Multiply(Complex a, Complex b); /// <summary>
/// 取模
/// </summary>
[OperationContract]
double Modulus(Complex a);
}
}

数据契约 Complex.cs:

 namespace Cookiezhi.WcfStudy.Contracts.DataContracts
{
[DataContract(Namespace = "http://www.cookiezhi.com/data/complex")]
public class Complex
{
/// <summary>
/// 实数
/// </summary>
[DataMember]
public double A { get; set; } /// <summary>
/// 虚数
/// </summary>
[DataMember]
public double B { get; set; }
}
}

服务契约实现 ComplexCalculateService:

 namespace Cookiezhi.WcfStudy.Services
{
public class ComplexCalculateService : IComplexCalculate
{
public Complex Add(Complex a, Complex b)
{
return new Complex()
{
A = a.A + b.A,
B = a.B + b.B
};
} public Complex Subtract(Complex a, Complex b)
{
return new Complex()
{
A = a.A - b.A,
B = a.B - b.B
};
} public Complex Multiply(Complex a, Complex b)
{
return new Complex()
{
A = a.A * b.A - a.B * b.B,
B = a.A * b.B + a.B * b.A
};
} public double Modulus(Complex a)
{
return Math.Sqrt(a.A * a.A + a.B * a.B);
}
}
}

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

 <system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="mexBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors> <services>
<service name="Cookiezhi.WcfStudy.Services.ComplexCalculateService" behaviorConfiguration="mexBehavior">
<endpoint address="" binding="basicHttpBinding" contract="Cookiezhi.WcfStudy.Contracts.ServiceContracts.IComplexCalculate" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:9999/complexcalcservice"/>
</baseAddresses>
</host>
</service>
</services> </system.serviceModel>

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

 namespace Cookiezhi.WcfStudy.Hosting
{
class Program
{
static void Main(string[] args)
{
using(ServiceHost host = new ServiceHost(typeof(ComplexCalculateService)))
{
host.Opened += delegate
{
Console.WriteLine("Service {0} started", host.Description.Name);
}; host.Open(); Console.ReadKey();
}
}
}
}

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

再看一下WSDL

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

App.config

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

Main方法

 namespace Cookiezhi.WcfStudy.Client
{
class Program
{
static void Main(string[] args)
{
using(ChannelFactory<IComplexCalculate> factory = new ChannelFactory<IComplexCalculate>("ComplexCalculateService"))
{
IComplexCalculate proxy = factory.CreateChannel(); Complex a = new Complex() { A = , B = };
Complex b = new Complex() { A = , B = };
Complex result = null; result = proxy.Add(a, b);
Console.WriteLine("Add result is {0} + {1}i", result.A, result.B); Console.ReadKey();
}
}
}
}

调用服务:

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

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

客户端拦截器 IClientMessageInspector

提供两个接口

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

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

服务端拦截器 IDispatchMessageInspector

他也提供两个接口

AfterReceiveRequest:invoke操作之前执行

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

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

实现接口 MessageInspector.cs

 namespace Cookiezhi.WcfStudy.Hosting.MessageInspect
{
public class MessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
Console.WriteLine(request.ToString());
return DateTime.Now;
} public void BeforeSendReply(ref Message reply, object correlationState)
{
Console.WriteLine(reply.ToString());
DateTime requestTime = (DateTime)correlationState; var duration = DateTime.Now - requestTime;
Console.WriteLine(duration);
}
}
}

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

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

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

 namespace Cookiezhi.WcfStudy.Hosting.MessageInspect
{
public class MessageInspectorBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
} public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
} public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MessageInspector()); } public void Validate(ServiceEndpoint endpoint)
{
}
}
}

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

 namespace Cookiezhi.WcfStudy.Hosting.MessageInspect
{
public class MessageInspectorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(MessageInspectorBehavior); }
} protected override object CreateBehavior()
{
return new MessageInspectorBehavior();
}
}
}

下面就是配置这个行为了

App.config

 <?xml version="1.0" encoding="utf-8" ?>
<configuration> <system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="messageInspector" type="Cookiezhi.WcfStudy.Hosting.MessageInspect.MessageInspectorExtensionElement, Cookiezhi.WcfStudy.Hosting"/>
</behaviorExtensions>
</extensions> <behaviors>
<serviceBehaviors>
<behavior name="mexBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="messageInspector">
<messageInspector />
</behavior>
</endpointBehaviors>
</behaviors> <services>
<service name="Cookiezhi.WcfStudy.Services.ComplexCalculateService" behaviorConfiguration="mexBehavior">
<endpoint address="" binding="basicHttpBinding" contract="Cookiezhi.WcfStudy.Contracts.ServiceContracts.IComplexCalculate" behaviorConfiguration="messageInspector" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:9999/complexcalcservice"/>
</baseAddresses>
</host>
</service>
</services> </system.serviceModel> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

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

然后我们尝试一下

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

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

[WCF]设置拦截器捕捉到request和reply消息的更多相关文章

  1. 【转】WCF设置拦截器捕捉到request和reply消息

    原文:https://www.cnblogs.com/yanglang/p/7063743.html 我们需要拦截消息,并把消息打印出来,那么我们就需要一个拦截器,叫做MessageInspector ...

  2. Spring拦截器中通过request获取到该请求对应Controller中的method对象

    背景:项目使用Spring 3.1.0.RELEASE,从dao到Controller层全部是基于注解配置.我的需求是想在自定义的Spring拦截器中通过request获取到该请求对应于Control ...

  3. Spring Boot2.0 设置拦截器

    所有功能完成 配置登录认证 配置拦截器 在spring boot2.0 之后 通过继承这个WebMvcConfigurer类 就可以完成拦截 新建包com.example.interceptor; 创 ...

  4. 【spring boot】在自定义拦截器中从request中获取json字符串

    又这样的需求,需要在自定义的拦截器中获取request中的数据,想获取到的是JSON字符串 那需要在拦截器中写这样一个方法 public static String getOpenApiRequest ...

  5. spring boot拦截器中获取request post请求中的参数

    最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题. 首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取 ...

  6. 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.

    由于 request中getReader()和getInputStream()只能调用一次 在项目中,可能会出现需要针对接口参数进行校验等问题. 因此,针对这问题,给出一下解决方案 实现方法:先将Re ...

  7. axios 设置拦截器 全局设置带默认参数(发送 token 等)

    应用场景: 1,每个请求都带上的参数,比如token,时间戳等. 2,对返回的状态进行判断,比如token是否过期 代码如下: [javascript] view plain copy axios.i ...

  8. 在SSM框架中我设置拦截器filter不能通过注解获取到实现类

    我在用注解注入实现类的时候,出现了这样的错误:如以下截图: 这个地方报出的错误是说明我的一个接口类型的类没有获取到,后来我就想要是我的实现类没有获取到那么我就直接new一个实现类然后再进行调用就会出现 ...

  9. spring boot拦截器中获取request post请求中的参数(转)

    文章转自 https://www.jianshu.com/p/69c6fba08c92

随机推荐

  1. python 学习中遇到的问题

    一.安装pip中遇到的问题. 出现错误:ImportError:DLL load failed :%1不是有效的win32应用程序 出现问题解答: 主要是由于安装的python版本和所下载的安装包版本 ...

  2. C#MongoDB使用实践

    9.5更新:更方便的启动命令 1)在D:\MongoDB中新建mongo.config文件,内容为 #启动mongod:mongod.exe --bind_ip 127.0.0.1 --logpath ...

  3. Linux 忘记密码解决方法

    很多朋友经常会忘记Linux系统的root密码,linux系统忘记root密码的情况该怎么办呢?重新安装系统吗?当然不用!进入单用户模式更改一下root密码即可. 步骤如下: 重启linux系统 3  ...

  4. SPSS数据分析—分段回归

    在SPSS非线性回归过程中,我们讲到了损失函数按钮可以自定义损失函数,但是还有一个约束按钮没有讲到,该按钮的功能是对自 定义的损失函数的参数设定条件,这些条件通常是由逻辑表达式组成,这就使得损失函数具 ...

  5. java 多线程—— 线程让步

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  6. ets查询:查询表中的具体一列的所有值

    比如要查询goods表中的ID这一列的所有值: P = [{#goods{upgrade='$1',_ = '_'},[],['$1']}] 要查询ID和Upgrade这两列的值: P2 = [{#g ...

  7. Java mysql 日期相关

    获取当前系统时间和日期并格式化输出: import java.util.Date;import java.text.SimpleDateFormat; public class NowString { ...

  8. 使用UISegmentedControl的一个注意事项

    NSArray* array = [[NSArray alloc]initWithObjects:@"机会",@"联系人", nil]; //先确定segmen ...

  9. myeclipse中文乱码,JSP页面乱码

    一.设置新建常见文件的默认编码格式,也就是文件保存的格式.在不对MyEclipse进行设置的时候,默认保存文件的编码,一般跟简体中文操作系统(如windows2000,windowsXP)的编码一致, ...

  10. UISegmentedControl的详细使用

    当用户输入不仅仅是布尔值时,可使用分段控件(UISegmentedControl).分段控件提供一栏按钮(有时称为按钮栏),但只能激活其中一个按钮.分段控件会导致用户在屏幕上看到的内容发生变化.它们常 ...