Friday, November 9, 2012

Adding custom WCF endpoint behavior in client code

Endpoint behaviors are used to customize the runtime behavior of WCF clients. It's very useful, for example, if we want to send some special information to WCF service with each call from client.

Suppose, we have ASP.NET application and we need to send current user identity with every call to our IPersonalService.

First of all, we need to configure our WCF client. We use Castle Windsor WCF Facility to do this. In Application_Start handler of Global.asax we need to create WindsorContainer, add WcfFacility, and register our IPersonalService with custom SecureEndpointBehavior:

 Container = new WindsorContainer();  
 Container.AddFacility<WcfFacility>();  
 var personalServiceUrl = ConfigurationManager.AppSettings["PersonalServiceUrl"];  
 Container.Register(Component.For<IPersonalService>().AsWcfClient(WcfEndpoint.BoundTo(new BasicHttpBinding()).At(personalServiceUrl).AddExtensions(new SecureEndpointBehavior())));  

To create desired endpoint behavior we need to implement actually endpoint behavior and message inspector.

Example of endpoint behavior class:
 public class SecureEndpointBehavior : BehaviorExtensionElement ,IEndpointBehavior  
   {  
     public void Validate(ServiceEndpoint endpoint)  
     {  
     }  
     public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)  
     {  
     }  
     public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)  
     {  
     }  
     public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)  
     {  
       clientRuntime.MessageInspectors.Add(new SecureMessageInspector());  
     }  
     protected override object CreateBehavior()  
     {  
       return new SecureEndpointBehavior();  
     }  
     public override Type BehaviorType  
     {  
       get { return typeof(SecureEndpointBehavior); }  
     }  
   }  

Example of message inspector class:
 public class SecureMessageInspector : IClientMessageInspector  
   {          
     public object BeforeSendRequest(ref Message request, IClientChannel channel)  
     {        
       var siteUser = DependencyResolver.Current.GetService<ISiteUser>();  
       var header = new MessageHeader<Guid>(siteUser.UserId);  
       var untypedHeader = header.GetUntypedHeader("UserToken", "MyProject");  
       request.Headers.Add(untypedHeader);        
       return request;  
     }  
     [DebuggerStepThrough]  
     public void AfterReceiveReply(ref Message reply, object correlationState)  
     {  
     }  
   }  

As you can see, SecureEndpointBehavior class just adds SecureMessageInspector instance to list of run-time message inspectors. Our SecureMessageInspector is very simple: it just creates MessageHeader, puts siteUser.UserId into, and adds this header to the list of headers.

Now, on IPersonalService side you can retrieve user id under which the call was made to the service. In IPersonalService implementation, you can use the following command to retrieve user id:
 var userId = OperationContext.Current.IncomingMessageHeaders.GetHeader<Guid>("UserToken", "MyProject");  

No comments:

Post a Comment