When building Service communication applications using Windows Communication Foundation, we often come to a situation where we have multiple clients communicating with WCF Service and we need to pass additional parameters from client to service. This may be due to number of reasons such as sharing a unique customer ID to identify certain elements for that particular client. In such scenarios, for every communication between client and server, you need this unique ID to treat each client accordingly.

Client-Server-Customer-Id-Parameter-WCF

In a typical disconnected environment over the internet you need to pass such data on each call to service and of course passing in each Service Method or Operation Call is confusing and not appropriate.

A good Solution is to pass additional parameters in SOAP headers utilizing with the help of Custom headers in WCF. A SOAP envelope contains a header and a body. Method call and its parameters are transformed to SOAP body whereas SOAP header usually contains application-specific information (like authentication etc.)

 image

A simple way to achieve this in WCF is to add MessageHeader in your proxy class as in code snippet below:

[csharp]
public partial class TestServiceClient : ClientBase<Client.ServiceProxy.ITestService>, Client.ServiceProxy.ITestService
{
public TestServiceClient()
{
var header = new MessageHeader<string>("Customer Unique Id: 12345");
var untyped = header.GetUntypedHeader("Identity", "https://www.adilmughal.com");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
} 
//Other constructors and Service Method Calls
}
[/csharp]

However this is really NOT a suitable approach as if you would be generating proxy using svcutil.exe or using Visual Studio then it will replace your proxy code.

A Better Solution to solve this problem is to utilize custom behavior extension in WCF to pass additional parameters in SOAP Message header. Following are the steps required on client:

1) Implement IClientMessageInspector to create custom message inspector

[csharp]
public class MyMessageInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply,object correlationState)
{
Console.WriteLine("SOAP Response: {0}", reply.ToString());
}

public object BeforeSendRequest(ref Message request,IClientChannel channel)
{
var header = new MessageHeader<string>("Customer Unique Id: 12345");
var untyped = header.GetUntypedHeader("Identity", "https://www.adilmughal.com");
request.Headers.Add(untyped);Console.WriteLine("SOAP Request: {0}", request.ToString());
return null;
} 
}
[/csharp]

2) Create a custom behavior class implementing IEndPointBehavior and BehaviorExtensionElement. Then add the custom message inspector in runtime in ApplyClientBehavior method as shown in code snippet below:

[csharp]
public class CustomBehavior : BehaviorExtensionElement, IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}

public void Validate(ServiceEndpoint endpoint)
{
}

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

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

[/csharp]

3) Finally, register behavior in .config under

[xml]
<behaviors>
<endpointBehaviors>
<behavior>
<customInspector />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="customInspector" type="Client.CustomBehavior, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
[/xml]

That is all you have to do on client end to pass additional parameter in SOAP header using Custom Behavior in WCF.

To retrieve parameter passed in header on server side, you need to use OperationContext object

[csharp]
MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
string customParameter = headers.GetHeader&lt;string&gt;("Identity", "https://www.adilmughal.com");
return string.Format("You entered: {0}", customParameter);
[/csharp]

This would achieve the objective. Following is the detail of SOAP Envelope:

SOAP Request:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/ITestService/GetDataAction>
<Identity xmlns="https://www.adilmughal.com">Customer Unique Id: 12345Identity>
s:Header>
<s:Body>
<GetData xmlns="http://tempuri.org/">
<value>123value>
GetData>
s:Body>
SOAP Response:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<GetDataResponse xmlns="http://tempuri.org/">
<GetDataResult>You entered: Customer Unique Id: 12345GetDataResult>
GetDataResponse>
s:Body>
s:Envelope>

In this post we saw how to create custom SOAP header in WCF to pass parameter from client to server using WCF behavior extension. Hope this helps.





18 Comments

usama khalil · October 24, 2011 at 5:55 am

Thanks for this nice post..

Adil Mughal · October 24, 2011 at 6:19 am

@Usama Thanks for the compliment!

Dan · April 20, 2012 at 7:09 pm

This was very helpful! Thanks so much. I’ve read through about 20 different ways to do this today and this was the only one I could get to work.

I used silverlight, so to actually add the custom endpoint behavior I had to use this: http://silverlightedweb.blogspot.com/2011/08/adding-custom-endpoint-behavior-at.html

Adil Mughal · April 23, 2012 at 4:46 am

@Dan: Glad to know it helped. For Silverlight, I have published another blog post that may be of any help to you.
https://www.adilmughal.com/2011/10/wcf-custom-header-with-silverlight.html

Jitender Pal · May 7, 2012 at 12:51 pm

This part does not work for me .IT does not recognise customInspector .

Adil Mughal · May 7, 2012 at 1:41 pm

@Jitendar: Can you share some details? or email me via contact form?

Guest · May 11, 2012 at 7:49 am

Thanks a lot! This solved exactly my problem, great article!

Riaan :) · May 13, 2012 at 11:53 am

I have the same problem. In the app.config file the ” ” does not work. It says behavior has invalid child element. I have a winforms app and it is done in VB.

utòpiq · May 15, 2012 at 1:54 pm

I’ve the same problem as Jitender and Riaan:

The element ‘behavior’ has invalid child element ‘customInspector’. List of possible elements expected: ‘clientVia, callbackDebug, callbackTimeouts, clear, clientCredentials, transactedBatching, dataContractSerializer, dispatcherSynchronization, remove, synchronousReceive, enableWebScript, webHttp, endpointDiscovery, soapProcessing’.

Web.config

Adil Mughal · May 16, 2012 at 5:48 am

@Utopiq and Riaan: Can you please share some sample code?
Are you using .NET framework client profile or full one?

Adil Mughal · May 16, 2012 at 5:57 am

@jitendar: Your provided email address is bouncing back. Please provide alternative.

Anonymous · May 17, 2012 at 5:00 pm

Hi Adil, if you have a solution for utopiq, Jitender, and Riaan could you please post it? I have the same problem in web.config.

The element ‘behavior’ has invalid child element ‘customInspector’. List of possible elements expected: ‘clientVia, callbackDebug, callbackTimeouts, clear, clientCredentials, transactedBatching, dataContractSerializer, dispatcherSynchronization, remove, synchronousReceive, enableWebScript, webHttp, endpointDiscovery, soapProcessing’.

Kevin Parkinson · June 25, 2012 at 10:18 pm

Try …

Anonymous · October 19, 2012 at 3:09 pm

I have a .net 4.0 web forms application consuming a service. I got the same error about the web.config, the customInspector was not a recognized element inside

I used the silverlight solution instead, and registered the behavior programmatically as per this post:
https://www.adilmughal.com/2011_10_01_archive.html

ServiceProxy.TestServiceClient proxy = new ServiceProxy.TestServiceClient();proxy.Endpoint.Behaviors.Add(new CustomBehavior());

And this solved my problem

Adil Mughal · October 21, 2012 at 4:10 pm

Thanks for sharing your experience and resolution…

shanmugam · May 3, 2013 at 6:55 am

nice article. thanks for sharing

NANDAKISHOR GAIKWAD · May 28, 2013 at 9:21 am

Nandu -: can u please attach demo project of this…..

Dileep Reddy · January 23, 2014 at 10:46 am

Hi Adil,
I get the following error after modifying the web.config file as you said.
The type ‘Client.CustomBehavior, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ registered for extension ‘custom Inspector’ could not be loaded.
Can you please share the code sample.
My email id : dileepkrso@gmail.com

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *