Miscellaneous Debris

Avner Kashtan's Frustrations and Exultations

Adding custom headers to every WCF call - a solution

At last, a solution presented itself. While I must admit that at first I was very skeptical of the extensibilty model for WCF which seemed far too involved and complicated, but after implementing a simple extension I must say it's simple and quite intuitive.

My goal was to have several custom headers added to each call made through a proxy, rather than manually adding them to each call's OperationContext. With a little help from Ralph Squillace's blog, I was able to get an extension up and running within minutes, and it Just Works.

The first item to build is the actual extension logic. In this case, I needed an IProxyMessageInspector object that inspects each outgoing message and adds the custom headers:

public class ContextPusher : IProxyMessageInspector
    {
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            // Do nothing.
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            MessageHeader myHeader = new MessageHeader("HeaderValue").GetUntypedHeader("MyHeader", "ns");
            request.Headers.Add(
myHeader);
            return null;
        }
    }
}

Now we want to attach that inspector to proxy. We do that wth Behavior objects. This can be done on an operation-by-operation basis or for all operations on a given channel. We can make the same class implement both behaviors, for flexibility:

public class CallContextAttribute : Attribute, IChannelBehavior, IOperationBehavior
    {
        #region IOperationBehavior Members

        public void ApplyBehavior(OperationDescription description, ProxyOperation proxy, BindingParameterCollection parameters)
        {      
            // Add my MessageInspector to each message sent by the proxy.
            proxy.Parent.MessageInspectors.Add(new ContextPusher());
  
        }

        public void ApplyBehavior(OperationDescription description, DispatchOperation dispatch, BindingParameterCollection parameters)
        {
            // No server-side behaviors for now.
        }

        #endregion
               
        #region IChannelBehavior Members

        public void ApplyBehavior(ChannelDescription description, ProxyBehavior behavior, BindingParameterCollection parameters)
        {
            // Add the MessageInspector to every message sent through the channel.
            behavior.MessageInspectors.Add(new ContextPusher());
        }

        #endregion
    }


And then simply put it on a Service or Operation.
I think in this case, putting the attribute on both will result in an error when trying to add duplicate headers. But this allows me flexibility in adding the headers only to certain calls.

[ServiceContract]
[CallContext]
public interface ILocalizationServices
{
   [OperationContract]
   [CallContext]
   string DoSomething(string param);
}


I think this is the first time I got really excited by the WCF framework and the ease of using and extending it. This is FUN.

Comments

Vishal said:

Hi Am having same requiremnts i need to pass Headers to 3rd Party Web Service Using WCF. I just know tht the Web service Need some headers which i need to pass. I cant modify Web Service whatevr i have to do is through WCF cleint. Can u please explain the code above i mean ContextPusher & CallContextAttribute shld be the class on Client Application or on Service Side?
# May 5, 2006 5:16 AM

vishal said:

Hi Can u please send me SERVICE & WCF Client Code. I cant modify 3rd Party Web Service still i want to pass headers using WCF behaviour. Please PLease Help me...if u can mail me the code tht will be of great help am using FEB CTP

# May 5, 2006 6:57 AM

Miscellaneous Debris said:

I've been using WCF for the past few months and on the whole, I think the programming model works.

# July 31, 2006 6:49 AM

GKALLURI said:

This is pretty neat way doing than using the OperationContext to do the same.

Can you please send me the client and server code.

You can email at giri.kalluri@gmail.com

# November 15, 2007 5:53 PM

Saran said:

Hi, can u share this code?

# July 3, 2008 7:31 AM

Smith said:

How can we read this header from Server side??

# September 2, 2008 10:10 AM

Henry said:

This is exactly what I want to do, too.  Can you send me the client and server code?

My email is henrylyyang@yahoo.com

--Henry

# January 6, 2009 2:38 PM

Jim Meehan said:

Can you send me the sample client and server code? Thanks, jb_meeh@yahoo.com

# March 9, 2009 2:29 PM

dalbong2 said:

I found your post today while surfing around the web.

This is exactly what i need.

Can you send me the code of your sample?

My email is hajimaru1@hotmail.com

# June 26, 2009 5:07 AM

Ketan said:

Hi ,

This is a neat bit of coding.

Can you please send the client and server side code of this sample to me at ketankalia@gmail.com

Thanks

# July 25, 2009 2:11 PM

Aaron said:

Hi,

This is really cool. I'm also really interested in your client and server side code of this sample. Kindly mail me at, apeterin@yahoo.com

Thanks

Aaron

# July 30, 2009 1:24 AM

Sean said:

Thanks for the post.

I am trying to follow this and one thing that is making this VERY difficult is that you didn't post the "using" statements that are required to implement this code.

Sean

# October 16, 2009 5:52 PM

Dean said:

Please send source Code, this looks awesome and exactly what I need.

# February 8, 2010 9:56 AM

Y2KPRABU said:

That was way too old guys in 2006 , lots of classes and interfaces have changed , check the latest code here

public class ContextPusher : IClientMessageInspector

   {

       public void AfterReceiveReply(ref Message reply, object correlationState)

       {

           // Do nothing.

       }

       public object BeforeSendRequest(ref Message request, IClientChannel channel)

       {

           MessageHeader myHeader = MessageHeader.CreateHeader("MyHeader", "ns", "HeaderValue");

           request.Headers.Add(myHeader);

           return null;

       }

   }

   public class CallContextAttribute : Attribute,  IOperationBehavior ,IContractBehavior

   {

       #region IOperationBehavior Members

       void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)

       {

       }

       void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)

       {

          clientOperation.Parent.MessageInspectors.Add      (new ContextPusher());    

       }

       void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)

       {

           //throw new NotImplementedException();

       }

       void IOperationBehavior.Validate(OperationDescription operationDescription)

       {

          // throw new NotImplementedException();

       }

       #endregion

       #region IContractBehavior Members

       void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

       {

       }

       void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)

       {

           clientRuntime.MessageInspectors.Add(new ContextPusher());    

       }

       void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)

       {

           //throw new NotImplementedException();

       }

       void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)

       {

           //throw new NotImplementedException();

       }

       #endregion

   }

# February 11, 2010 8:22 AM

Kangkan said:

It seems fine where I am using WCF/.NET on both the sides. But what should one do for interoperable services. In my case, I am writing a service on WCF/.NET and the binding is basicHTTP and I am consuming it from a gSOAP client on a c/Linux ARM processor based device.

I wish to send some or all content in the header in encrypted form so that it can not be sniffed. I however don't want to go for HTTPS as it will slow down the transactions. This is so because I am using GPRS to connect from the device and the bandwidth available is simply too poor.

Is there some solution for such a scenario?

# April 27, 2010 4:56 AM

bhuvan said:

send me the code for custom headers accessing form hotmail or gmail or any server..bhuvan.ram@hotmail.com

# October 8, 2010 5:13 AM

bmw said:

Would you send me your code at bmw_abc@hotmail.com? Thanks.

# October 19, 2010 6:57 PM

vivek said:

I have tried all possible way to solve this issue from last 10 days. Till issue exist.

I am having the below setup.

WCF Client <===TCP Binding==> WCF Routing Service <==== basicHTTPBinding====> WCF Service

My requirement is need to add the SessionID in the Cookie in the WCF Routing service.

I am using the  IClientMessageInspector in Routing service as below and adding the HttpRequestMessageProperty  properly. Before returning i check that cookie is added.

However, at the WCF server side i seen that Message.Properties is not received ( blank).

Not  sure what is problem.

Pupublic  object BeforeSendRequest(ref System.ServiceModel.Channels.Message request,

 System.ServiceModel.IClientChannel channel)

{

   HttpRequestMessageProperty httpRequestMessage;

   object httpRequestMessageObject;

   if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))

   {

       httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;

       if (string.IsNullOrEmpty(httpRequestMessage.Headers[USER_COOKIEE]))

       {

           httpRequestMessage.Headers[USER_COOKIEE] = this.m_Session;

       }

   }

   else

   {

       httpRequestMessage = new HttpRequestMessageProperty();

       httpRequestMessage.Headers.Add(USER_COOKIEE, this.m_Session);

       request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);

   }

   return null;

}

Also , i tried using the OperationContextScope  as below , till unable to send the Custom HTTP headers at WCF service.

I checked headers in the Routing service all added headers exist, but when i see at WCF service not there. Please help me to resolve this issue.

public object BeforeSendRequest(ref Message request, IClientChannel channel)

       {

get

           HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();

          httpRequestProperty.Headers.Add(HttpRequestHeader.Cookie, "CookieTestValue");

           using (OperationContextScope scope = new OperationContextScope(channel))  //Create scope using the channel.

           {

               OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

               //OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequestProperty);

                            //Also i added transport property as below.

               OperationContext.Current.OutgoingMessageProperties.Add("TestHeader1"," TestHeaderVal 1213");

           }

return null

}

Please let me know what is solution for this issue. Waiting for immediate reply.

-vivek

# April 19, 2011 9:56 AM

Denis Kochnev said:

Hi,

I am currently working with WCF Framework 4. I added 2 options how to do it.

# May 22, 2011 4:10 PM

puntynoemi said:

order an <a href=coachbagsusa.livejournal.com/>coach bags usa</a>   and get big save   online shopping

# December 24, 2011 9:38 AM

puntydallas said:

cheap <a href=dvd-to-nexu-sone.weebly.com/>dvd to nexus one</a>   to get new coupon   for more detail

# January 4, 2012 5:58 AM

Bymnjonell said:

to buy   online shopping <a href=blindfish.com/index.php  , just clicks away

# January 16, 2012 11:23 PM

Jolavods said:

order an   for less <a href=oshaforum.com/.../a>   and get big save

# January 20, 2012 7:50 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)