WCF Extension : Inject and Inspect Custom Message

While working with WCF, we often need transfer some kind of data in message headers. For example, in order to authenticate the caller of WCF service, we need pass username and password into the message header, then in the service side retrieve them and validate them. But how can we inject a custom message on WCF client side and retrieve it on WCF service side? The key is System.ServiceModel.Dispatcher.IClientMessageInspector and System.ServiceModel.Dispatcher.IDispatchMessageInspector. To learn more about the two interfaces please refer to the following link on MSDN.

http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageinspector.aspx

http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.idispatchmessageinspector.aspx

Now, let's take a look at the definitions of interface IClientMessageInspector and IDispatchMessageInspector.

 
 

public interface IClientMessageInspector { void AfterReceiveReply(ref Message reply, object correlationState);
object BeforeSendRequest(ref Message request, IClientChannel channel); }
public interface IDispatchMessageInspector { object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext);
void BeforeSendReply(ref Message reply, object correlationState); }

On the client side, we need to implement a MessageInspector derived from IClientMessageInspector, while on the service side implement a MessageInspector derived from IDispatchMessageInspector.

As you can see both these interfaces define a couple of methods that allow to access the Message (System.ServiceModel.Channels.Message) just before sending it, regardless it is a Request (IClientMessageInspector) or a Response (IDispatchMessageInspector), and just after receiveing it, again regardless its direction.

Next, I will add MessageInspectors into my sample project that I hvae been using in previous blogs.

1. Define IClientMessageInspector Interface

In VS2008 Solution Explorer, right-click "ServiceHost" solution, Add New Project, select "Silverlight" as project type, and "Silverlight Class Library" as template, then input "SilverlightMessageInspector" as project name, click "OK" button.

Add reference to "System.ServiceModel.dll".

Right-click "SilverlightMessageInspector" project, Add New Item, select "Class" as template, Input "IClientMessageInspector.cs" as name,click "OK" button. The IClientMessageInspector.cs looks like below.

 
 

using System.ServiceModel; using System.ServiceModel.Channels;

namespace SilverlightMessageInspector { public interface IClientMessageInspector { object BeforeSendRequest(ref Message request, IClientChannel channel);
void AfterReceiveReply(ref Message reply, object correlationState); } }

2. Implement IClientMessageInspector Interface

Add a class "SecurityTokenMessageInspector" to implment IClientMessageInspector interface. Here is the sample code.

 
 

using System.ServiceModel; using System.ServiceModel.Channels;

namespace SilverlightMessageInspector
{ public class SecurityTokenMessageInspector : IClientMessageInspector { private string userToken;

public SecurityTokenMessageInspector(string userToken) { this.userToken = userToken; }

public object BeforeSendRequest(ref Message request, IClientChannel channel) { request.Headers.Add(MessageHeader.CreateHeader("SecurityToken", "", userToken)); return null; }

public void AfterReceiveReply(ref Message reply, object correlationState){ } } }

3. Extend BasicHttpBinding for Silverlight

In order to make the SecurityTokenMessageInspector work, we need to define a "MessageInspectorBasicHttpBinding" calss which extends the "BasicHttpBinding" class. We inject the IClientMessageInspector type into MessageInspectorBasicHttpBinding's constructor. Let's look at the code.

 
 

using System.ServiceModel; using System.ServiceModel.Channels;

namespace SilverlightMessageInspector { public class MessageInspectorBasicHttpBinding : BasicHttpBinding
{
private MessageInspectorBindingElement channelBindingElement;

public MessageInspectorBasicHttpBinding(IClientMessageInspector messageInspector)
{
channelBindingElement = new MessageInspectorBindingElement();
channelBindingElement.MessageInspector = messageInspector;
}

public override BindingElementCollection CreateBindingElements()
{
BindingElementCollection bindingElements = base.CreateBindingElements();
bindingElements.Insert(bindingElements.Count - 1, channelBindingElement);

return bindingElements;
}
}
}

4. Define a BindingElement for MessageInspectorBasicHttpBinding

 
 

public class MessageInspectorBindingElement : BindingElement
{
public IClientMessageInspector MessageInspector { get; set; }
public MessageInspectorBindingElement(){ }

......
}

5. Define MessageInspectorChannel and MessageInspectorChannelFactory

 
 

public class MessageInspectorChannel : ChannelBase, IRequestChannel
{
private IRequestChannel innerChannel;
private IClientMessageInspector messageInspector;
......
}

public class MessageInspectorChannelFactory : ChannelFactoryBase
{
private IChannelFactory innerChannelFactory;
private IClientMessageInspector messageInspector;

public MessageInspectorChannelFactory(IChannelFactory innerChannelFactory, IClientMessageInspector messageInspector)
{
this.messageInspector = messageInspector;
this.innerChannelFactory = innerChannelFactory;
}
......
}

The Silverlight side work is ok, now let's turn to the service side.

6. Implement IDispatchMessageInspector Interface

Add a class "WcfSecurityTokenMessageInspector" under the project "WcfServiceAuthentication", which extends the IDispatchMessageInspector interface. Look at the class code.

 
 

using System.ServiceModel.Dispatcher;

namespace WcfServiceAuthentication
{
class WcfSecurityTokenMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
int index = request.Headers.FindHeader("SecurityToken", "");
if (index >= 0)
{
string token = request.Headers.GetHeader(index);

// validate the security token here....
}

return null;
}

public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{

}
}
}

In order to configure these message inspectors we can use a custom behavior. Behaviros are classes that extend the service model defining custom extensions for: contracts, endpoints, services, operations. Here I use the endpoint bahavior.

7. Implement IEndpointBehavior Interface

 
 

using System.ServiceModel.Description;

namespace WcfServiceAuthentication
{
class WcfSecurityTokenHeaderBehavior : IEndpointBehavior
{
#region IEndpointBehavior Members

public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}

public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
}

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
WcfSecurityTokenMessageInspector inspector = new WcfSecurityTokenMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}

public void Validate(ServiceEndpoint endpoint)
{
}

#endregion
}
}

As you can see I implement the IEndpointBehavior interface, which defines three methods (AddBindingParameter, ApplyClientBehavior, ApplyDispatchBehavior). The one I'm interested on is the ApplyDispatchBehavior that relates to the service-side. This method receives a parameter of type EndpointDispatcher that allows to add custom Message Inspectors instance to the service dispatching environment. Because we're defining an Endpoint Behavior, this behavior affects a single endpoint of a service. To map the behavior to the service endpoint we can use a custom configuration element in the configuration file of the service host. In this sample I used a custom configuration element. To do that we need a custom type describing the configuration element. It is a type inherited from BehaviorExtensionElement.

8. Extends BehaviorExtensionElement Class

Add reference to "System.Configuration.dll" under project "WcfServiceAuthentication".

Add a class "WcfSecurityTokenHeaderBehaviorExtensionElement" which extends System.ServiceModel.Configuration.BehaviorExtensionElement class. It look like below.

 
 

using System;
using System.ServiceModel.Configuration;

namespace WcfServiceAuthentication
{
class WcfSecurityTokenHeaderBehaviorExtensionElement : BehaviorExtensionElement
{
public WcfSecurityTokenHeaderBehaviorExtensionElement()
{
}

public override Type BehaviorType
{
get
{
return typeof(WcfSecurityTokenHeaderBehavior);
}
}

protected override object CreateBehavior()
{
return new WcfSecurityTokenHeaderBehavior();
}
}
}

9. Config the MessageInspector and EndpointBehavior

The Web.config changed as below.

 
 




......









<!-- Service Endpoints --&gt
behaviorConfiguration="MessageInspectorBehavior" />
behaviorConfiguration="MessageInspectorBehavior" />
















So far we finished the whole prcess: implement MessageInspector, extend EndpointBehavior and make it configurable. Next I will use this technology to implement a WCF authentication by injecting a custom security token into message header.

[@more@]

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/13651903/viewspace-1034100/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/13651903/viewspace-1034100/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值