Share via


Adding a Message Header without using a MessageContract

Using Message contracts is quite a straight forward way of creating and adding message headers.But then again you might just want to add a header without going downt that route like this post by Kenny. You generally come across 2 scenarios where you want to add headers in every message or just for a particular set of operations that you would like to control. The code below shows you how to add headers for every operation using a Client behavior or just to a particular set calls using the OperationContextScope which would give you access to current operation context on the client side.

You can modify the outgoing message headers on using the OperationContext. If you are using a client instance(generated proxy then you can uset he inner channel ref: article) or else you can just use the channel factory and get the client channel.

Here the first operation is called without the a scoped header and the header is added only after the first call to the proxy happens. and the same operation can now access the header newly added header.

using System;

using System.Collections.Generic;

using System.Text;

using System.ServiceModel;

using System.ServiceModel.Description;

using System.ServiceModel.Channels;

using System.ServiceModel.Dispatcher;

namespace SoapHeaderSample

{

[ServiceContract]

public interface ICalculatorService

{

[OperationContract]

int Add(int a, int b);

}

public class CalculatorService : ICalculatorService

{

public int Add(int a, int b)

{

//Get the header in the operation

MessageHeaders hdrs = OperationContext.Current.IncomingMessageHeaders;

int hdrIndex = hdrs.FindHeader("BehaviorHeader", "BehaviorHeaderNS");

int scopeHdrIndex = hdrs.FindHeader("ScopedHeader", "ScopedHeaderNS");

Console.WriteLine("HeaderContent at service:" + hdrs.GetHeader<string>(hdrIndex));

if(scopeHdrIndex >=0)

Console.WriteLine("ScopedHeader Content at service:" + hdrs.GetHeader<string>(scopeHdrIndex));

return a + b;

}

}

class Program

{

static void Main(string[] args)

{

string addr = "net.tcp://localhost:5050/ServiceModelSamples";

Uri[] baseAddrs = new Uri[] { new Uri(addr) };

using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddrs))

{

host.AddServiceEndpoint(typeof(ICalculatorService), new NetTcpBinding(), "");

host.Open();

Console.WriteLine("Host listening at " + host.BaseAddresses[0]);

Console.ReadLine();

//Call the service

ChannelFactory<ICalculatorService> cf = new ChannelFactory<ICalculatorService>(new NetTcpBinding(), addr);

cf.Endpoint.Behaviors.Add(new EndpointBehaviorAddHeader());

ICalculatorService proxy = cf.CreateChannel();

try

{

using (OperationContextScope scope = new OperationContextScope(proxy as IClientChannel))

{

Console.WriteLine("\tResult " + proxy.Add(10, 100));

//Add the new header for this operation

Console.WriteLine("\nNew Header added.\n");

OperationContext.Current.OutgoingMessageHeaders.Add(

MessageHeader.CreateHeader("ScopedHeader", "ScopedHeaderNS", "Scoped header value"));

Console.WriteLine("\tResult " + proxy.Add(10, 100));

}

}

finally

{

IChannel c = proxy as IChannel;

if(c !=null && c.State == CommunicationState.Opened)

c.Close();

}

}

}

public class EndpointBehaviorAddHeader : IEndpointBehavior

{

public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

{}

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

{

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

}

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)

{}

public void Validate(ServiceEndpoint endpoint)

{}

}

public class MessageInspectorAddHeader : IClientMessageInspector

{

public void AfterReceiveReply(ref Message reply, object correlationState)

{}

public object BeforeSendRequest(ref Message request, IClientChannel channel)

{

MessageHeader hrd = MessageHeader.CreateHeader("BehaviorHeader", "BehaviorHeaderNS", "BehaviorHeader header content");

request.Headers.Add(hrd);

return null;

}

}

}

}

Comments

  • Anonymous
    January 04, 2007
    Good post. As a design issue I wonder which method is more desirable. By seperating the message inspector into a seperate assembly, this allows you to declaratively process header data for a particular service (as well as share it among services). I also like the idea of fine tuning the format of the message contract, particularly if you are designing it for public consumption and need to control the serialization process. Of course, there's no law that says you can't do both, right?

  • Anonymous
    January 04, 2007
    Ofcourse this is only a POC. The point is I wanted to make sure that people are aware that they have options and they are limited wiht the standard approach. Regarding inspectors. YOu usually want to decouple them since you might want to use them across services.  Also this is not an approach is not for new services where you want to do contract first and you know exactly what you already require in the header body etc.