Freigeben über


Adding Custom MessageHeader and HTTP header to a WCF method call in a Windows Store app or Windows Phone app

We frequently see customers ask about adding custom Message headers as well as HTTP headers to outgoing WCF requests. There are multiple approaches of achieving this, but in this blog we are going to discuss the most convenient way of adding these two different type of headers headers to the outgoing WCF method calls.

One of the reasons you may want to add these extra headers could be because you may be having a service that requires you to send either of these headers and the call may fail with an error if you do not add them to the request. This blog just shows how to do it. A MessageHeader is a SOAP Header that gets added to the outgoing SOAP Envelope of the WCF request. A SOAP Envelope is the entity body part of the HTTP request. Depending on whether your service implementation requires a Message Header or a HTTP header, you can change your WCF Client to add that information accordingly.

This blog contains a zip file which implements a WCF Service implementation written in C#, and two client projects in the form of a Windows Store app and a Windows Phone app project type based on C#. The WCF Service is a simple Calculator service that performs the basic Add, Subtract, Divide and Multiply operations. The client side projects only call the “Add” method, but they show how to add the MessageHeader and HTTP headers to the outgoing requests.

We start off by creating a blank Windows Store app and a Windows Phone app project type. Once the project is created, we add a Button and a TextBlock UI element to the MainPage.xaml and add a button click handler to the Button. Then we proceed with adding the required Service Reference to the WCF Service via the “Add Service Reference” option in Visual Studio.

The most important part of adding a MessageHeader or a HTTP Header to the outgoing request is to gain access to the OperationContext of the currently executing request. To summarize the two operations:

a.) To add a MessageHeader, we access OperationContext.Current.OutgoingMessageHeaders property and call the Add(…) method

b.) To add a HTTP Header, we access the OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] property and assign a HttpRequestMessageProperty to it.

The below code section shows how to retrieve the OperationContext and assign these properties…

 CalculatorServiceClient client = new CalculatorServiceClient();
 using (new OperationContextScope(client.InnerChannel))
 {
     //....we will add code here
 }

In the above code, CalculatorServiceClient is the auto-generated class of the Calculator service that was generated when you did “Add Service Reference”.

Once you create the OperationContextScope, you can add a MessageHeader to the outgoing request by accessing the OperationContext.Current.OutgoingMessageHeaders property and then calling the Add method to add the MessageHeader. We are using a custom object of type UserInfo that will automatically get serialized. We are using a custom object to show how you can not only pass in simple types – such as Strings or Integers, but also add complex types to the outgoing MessageHeader. The below code shows this:

 CalculatorServiceClient client = new CalculatorServiceClient();
 using(new OperationContextScope(client.InnerChannel)) 
 {
     // We will use a custom class called UserInfo to be passed in as a MessageHeader
     UserInfo userInfo = new UserInfo();
     userInfo.FirstName = "John";
     userInfo.LastName = "Doe";
     userInfo.Age = 30;
  
     // Add a SOAP Header to an outgoing request
     MessageHeader aMessageHeader = MessageHeader.CreateHeader("UserInfo", "https://tempuri.org", userInfo);
     OperationContext.Current.OutgoingMessageHeaders.Add(aMessageHeader);
  
 }

Similarly we add a HTTP header to the outgoing request by accessing the OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] property and assigning a HttpRequestMessageProperty. The below code shows you how to do this:

 CalculatorServiceClient client = new CalculatorServiceClient();
 using(new OperationContextScope(client.InnerChannel)) 
 {
     // Add a HTTP Header to an outgoing request
     HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
     requestMessage.Headers["MyHttpHeader"] = "MyHttpHeaderValue";
     OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
 }

Putting both these things together, we will end up with the below code that adds both – a MessageHeader as well as a HTTP Header to the outgoing HTTP request and then we call the AddAsync(..) method to add two numbers. The below approach shows you the Windows Store app way of calling the asynchronous WCF method.

 CalculatorServiceClient client = new CalculatorServiceClient();
 using(new OperationContextScope(client.InnerChannel)) 
 {
     // We will use a custom class called UserInfo to be passed in as a MessageHeader
     UserInfo userInfo = new UserInfo();
     userInfo.FirstName = "John";
     userInfo.LastName = "Doe";
     userInfo.Age = 30;
  
     // Add a SOAP Header to an outgoing request
     MessageHeader aMessageHeader = MessageHeader.CreateHeader("UserInfo", "https://tempuri.org", userInfo);
     OperationContext.Current.OutgoingMessageHeaders.Add(aMessageHeader);
  
     // Add a HTTP Header to an outgoing request
     HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
     requestMessage.Headers["MyHttpHeader"] = "MyHttpHeaderValue";
     OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
  
  
     double result = await client.AddAsync(20, 40);
     txtOut.Text = "Add result: " + result.ToString();
 }

The Windows Phone way of calling the WCF Service is slightly different, where we assign a Completed event handler that will get triggered when the method completes. The Windows Phone code looks like this:

 CalculatorServiceClient client = new CalculatorServiceClient();
 using (new OperationContextScope(client.InnerChannel))
 {
     UserInfo userInfo = new UserInfo();
     userInfo.FirstName = "Vince";
     userInfo.LastName = "Voe";
     userInfo.Age = 35;
  
     // Add a SOAP Header to an outgoing request
     MessageHeader aMessageHeader = MessageHeader.CreateHeader("UserInfo", "https://tempuri.org", userInfo);
     OperationContext.Current.OutgoingMessageHeaders.Add(aMessageHeader);
  
     // Add a HTTP Header to an outgoing request
     HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
     requestMessage.Headers["MyHttpHeader"] = "MyHttpHeaderValue";
     OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
  
     client.AddCompleted += client_AddCompleted;
     client.AddAsync(20, 40);
 }

If you collect a Network/ Fiddler trace of the call, you should see the following HTTP request that shows what the added information looks like. You can reference the following blog: https://blogs.msdn.com/b/wsdevsol/archive/2013/06/05/configure-the-windows-phone-8-emulator-to-work-with-fiddler.aspx that shows how you can configure your Windows Phone 8 Emulator to work with Fiddler.

Notice the <s:Header>…</s:Header> section for the MessageHeader and the MyHttpHeader HTTP header in the request below.

 POST / HTTP/1.1
 Content-Type: text/xml; charset=utf-8
 MyHttpHeader: MyHttpHeaderValue
 SOAPAction: "https://tempuri.org/ICalculatorService/Add"
 Host: <yourServer>:8001
 Content-Length: 544
 Expect: 100-continue
 Accept-Encoding: gzip, deflate
 Connection: Keep-Alive
  
 <s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
 <s:Header>
     <UserInfo xmlns="https://tempuri.org" xmlns:i="https://www.w3.org/2001/XMLSchema-instance">
         <Age xmlns="https://schemas.datacontract.org/2004/07/CustomMessageHeader">30</Age>
         <FirstName xmlns="https://schemas.datacontract.org/2004/07/CustomMessageHeader">John</FirstName>
         <LastName xmlns="https://schemas.datacontract.org/2004/07/CustomMessageHeader">Doe</LastName>
     </UserInfo>
 </s:Header>
 <s:Body>
     <Add xmlns="https://tempuri.org/">
         <n1>20</n1>
         <n2>40</n2>
     </Add>
 </s:Body>
 </s:Envelope>

Hopefully this blog will help you understand the differences between adding a MessageHeader and a HTTP header and how you can add them to an outgoing HTTP request when calling the WCF Service.

Please let me know if this helped you out!  Be sure to follow my and our team on twitter @prashantphadke and @WSDevSol.

Here are a few MSDN links to the WCF functionality we just used above:

MessageHeader Class: https://msdn.microsoft.com/en-us/library/system.servicemodel.channels.messageheader.aspx
OperationContext.Current Property : https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontext.current.aspx
OperationContext.OutgoingMessageHeaders Property : https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontext.outgoingmessageheaders.aspx
OperationContext.OutgoingMessageProperties Property: https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontext.outgoingmessageproperties.aspx

 

CustomMessageHeader.zip

Comments

  • Anonymous
    February 25, 2014
    Hi, How do you parse the Header? I tried something like the following to load another UserInfo class with the passed values: ... s:Header>    <UserInfo xmlns="http://mysite.com" xmlns:i="www.w3.org/.../XMLSchema-instance">      <Password xmlns="schemas.datacontract.org/.../Password>      <UserName xmlns="schemas.datacontract.org/.../UserName>    </UserInfo> .... I then re-defined:    public class UserInfo    {        public string UserName;        public string Password;    } And tried to parse the incoming request... OperationContext.Current.IncomingMessageHeaders.GetHeader<UserInfo>("UserInfo", "http://mysite..com") {MyNamespace.MyApp.WCF.UserInfo}    Password: null    UserName: null I'm guessing it has something to do with the different xmlns values that Password/Username  have vs the one you pass into GetHeader?   Also, do you know how to make the UserInfo class available through the WCF proxy instead of having to create it manually on the client side and server side?  I thought if you decorated it with DataContract or MessageHeader but I'm not seeing it when I generate the proxy class. Thanks.

  • Anonymous
    March 25, 2014
    Hello Is this possible when using "Add Web Reference" or is there another treatment ?? I was given a WSDL and I've not figured out yet how to add the HTTP header needed for the method call within the proxy objects.

  • Anonymous
    July 10, 2015
    Fantastic post!.

  • Anonymous
    July 10, 2015
    Great article.But is there anyway i can call the the add method outside of the operationcontext scope?

  • Anonymous
    August 12, 2015
    Great article.

  • Anonymous
    October 06, 2015
    Hi Dave, Has you find a solution for your question: ¿do you know how to make the UserInfo class available through the WCF proxy instead of having to create it manually on the client side and server side? Thanks in advance