当我们需要扩展WCF的功能,或者需要实现某些特定的功能,我们可以通过使用WCF的扩展定制功能(WCF extension)实现。
与WCF定制行为相关的namespace主要包括2个:
a. System.ServiceModel.Disptcher:
该namespace主要用来用来定制行为,他们可以用来扩展WCF的服务模型。
b. System.ServiceModel.Channels:
该namespace用来定义定制绑定元素,它们可以扩展WCF的信道层。
实现定制行为的步骤
实现定制行为一般分为3步:
1. 声明扩展:
声明所要提供的行为的类型, 例如是工作在客户端中以将发送的数据序列化到消息里,还是工作在服务中以管理服务类型的实例等等。
2. 附加扩展:
第2步需要将所定制的extension附加到相应的操作,终结点或者服务端行为上。
例如对于客户端来说:
- 当他是操作相关(Operation)的时候,则将该定制行为附加到操作上,即实现System.ServiceModel.Description.IOperationBehavior接口。
- 当他是终结点(Endppoint)相关的时候 ,则将该定制行为附加到终结点上,即实现System.ServiceModel.Description.IEndpointBehavior接口。
3. 告知(inform):
告知的作用就是将那些自己定义的扩展行为告知客户端运行时组件(ClientRunTime)或者服务端调度器(EndpointDispatcher)。
对于附加到操作上的扩展行为,只能采用programmatically的方式告知,而对于附加到终结点上的扩张行为,告知的方式有2种,分别为programmatically和administratively。
利用MessageInsepctor来扩展WCF行为是常见的情形。通过定制MessageInsepctor, 我们可以在消息中加入特定的消息头,来扩展WCF的功能,比如验证授权等。下面通过一个示例,详细讲解如何通过利用MessageInpector behaviour extension,从而实现在WCF 客户端发出请求之前,添加一个自定义Message Header,在WCF server端接受到该WCF request中,读取该Message Header并作出相应动作。
MessageInspector扩展作简要介绍
MessageInspector(消息检查器)既可以应用在客户端,又可以应用在服务器端。当然,应用于不同端时,其要实现的接口和附加的对象有所不同。
1. 首先介绍如何实现客户端的MessageInsepector扩展:
第一步:实现接口System.ServiceModel.Dispatcher.IClientMessageInspector
其共有2个方法要实现,即BeforeSendRequest和AfterReceiveReply,前者在请求发送之前被自动调用,后者在客户端接受到消息自动调用。如果客户端没有实现这2个接口,那么客户端发送和接受消息的行为就不会被重写,一切照旧。
其接口原形如下:
public object BeforeSendRequest(ref Message request, IClientChannel channel)
public void AfterReceiveReply(Message reply,object correlationState)
如下所示:假设我们在即将发出的消息中加入一个Message Header:"estHeader",则如下所示:
public class ClientMessageInspectorDemo : System.ServiceModel.Dispatcher.IClientMessageInspector,System.ServiceModel.Description.IEndpointBehavior { #region Implemmentation for IClientMesageInpector //=================================== //该方法会在服务器端reply返回后自动调用 public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) { } //该方法在客户端消息发送之前会被自动调用 public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) { Console.WriteLine("BeforeSendRequest is called"); request.Headers.Add(System.ServiceModel.Channels.MessageHeader.CreateHeader("testHeader","SecurityLog","该Message Header为测试之用")); return null; } }
第二步:将第一步的扩张行为附加在ClientRuntime上,即实现System.ServiceModel.Description.IEndpointBehavior的ApplyClientBehavior()方法。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Configuration; using System.ServiceModel.Dispatcher; using System.Configuration; namespace SecurityLog { public class ClientMessageInspectorDemo : System.ServiceModel.Dispatcher.IClientMessageInspector,System.ServiceModel.Description.IEndpointBehavior { public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) { } public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) { Console.WriteLine("BeforeSendRequest is called"); request.Headers.Add(System.ServiceModel.Channels.MessageHeader.CreateHeader("testHeader","SecurityLog","This Message Header is used for testing")); return null; } #endregion #region Implementation for IEndpointBehavior //================================== public void AddBindingParameters(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { return; } public void ApplyClientBehavior(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, ClientRuntime behavior) { //此处为Extension附加到ClientRuntime。 behavior.MessageInspectors.Add(this); // return; } public void ApplyDispatchBehavior(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint , EndpointDispatcher endpointDispatcher) { //如果是扩展服务器端的MessageInspector,则要附加到EndpointDispacther上了。 //endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this); } public void Validate(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint ) { return; } #endregion }
public class MyMesssageInspectorExtensionelement : System.ServiceModel.Configuration.BehaviorExtensionElement { public override Type BehaviorType { get { return typeof(ClientMessageInspectorDemo); } } protected override object CreateBehavior() { return new ClientMessageInspectorDemo(); } } }
第三步:将定制行为告知WCF,要通过配置方式告知WCF我们自定义扩展行为的存在,必须提供一个从抽象基类System.ServiceModel.Configuration.BehaviorExtensionElement的类。
public class MyMesssageInspectorExtensionelement : System.ServiceModel.Configuration.BehaviorExtensionElement { public override Type BehaviorType { get { return typeof(ClientMessageInspectorDemo); } } protected override object CreateBehavior() { return new ClientMessageInspectorDemo(); } }
然后通过适当配置即可,如下所示:
当客户端发出请求之后,我们可以看到BeforeSendRequest被首先调用,并被写入自定义的Message Header。
2. 下面介绍如何实现服务器端的MessageInspector行为扩展。
第一步:实现接口System.ServiceModel.Dispatcher.IDispatchMessageInspector(不是客户端的IClientMessageInspector)
其共有2个方法要实现,即BeforeSendRequest和AfterReceiveReply,前者在请求发送之前被自动调用,后者在客户端接受到消息自动调用。如果客户端没有实现这2个接口,那么客户端发送和接受消息的行为就不会被重写。
其接口原形如下:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
public void BeforeSendReply(ref Message reply,object correlationState)
第二步:附加
此时要实现的接口是 public void ApplyDispatchBehavior(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint , EndpointDispatcher endpointDispatcher),不再是附加到客户端时的 public void ApplyClientBehavior(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
第三步:与客户端类似。
经过以上配置后,在WCF service端就可以接受到写入自定义的Message Header的SOAP包。然后比如我们通过request.Headers.GetHeader<string>("testHeader","SecurityLog")将该testHeader的值获取,根据业务逻辑进行相应操作。
以下为到达服务器端的SOAP包和testHeader中的内容:
希望以上内容对您有所帮助
Winston