In WCF, headers can be accessed via an instance of the class OperationContext, which is accessible via the OperationContext.Current (when available).
The naive way to approach this problem is to simply use this property within the method of your service:
[ServiceContract]
public interface IMyService
{
[OperationContract]
void MyMethod();
}
internal class MyService: IMyService
{
public void MyMethod()
{
Console.WriteLine("My Method");
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("headerFromMethod", "namespace", "headerFromMethodValue"));
}
}
For completeness, the code used to host this service within the Console Application (no config required) is:
using (var serviceHost = new ServiceHost(typeof(MyService)))
{
var endpoint = serviceHost.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "http://localhost:9000");
serviceHost.Open();
Console.WriteLine("Open for business");
Console.ReadLine();
serviceHost.Close();
}
A .NET client would access the headers like this:
var channel = ChannelFactory<IMyService>.CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:9000"));
var contextChannel = channel as IContextChannel;
using (new OperationContextScope(contextChannel))
{
channel.MyMethod();
var incommingHeaders = OperationContext.Current.IncomingMessageHeaders;
var header = incommingHeaders.GetHeader<string>("headerFromMethod", "namespace");
Console.WriteLine("Header from server: " + header);
}
If you have Fiddler, you can also see the headers using this tool.
Whilst this method will do what you want, it is questionable whether you want to mix your business logic (contained within the implementation of IMyService), and the logic controlling the "out-of-band" information attached to the message.
A cleaner separation is gained by implementing IDispatchMessageInspector, which allows you to intercept calls on the server and modify the message as it comes in and out:
public class ServerInterceptor: IDispatchMessageInspector, IEndpointBehavior
{
object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
{
reply.Headers.Add(MessageHeader.CreateHeader("header", "namespace", "headervalue"));
}
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
}
void IEndpointBehavior.Validate(ServiceEndpoint endpoint){}
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){}
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime){}
}
The headers are accessed from a .NET client in the same way as before. It's worth noting that you can pass information from the AfterReceiveRequest method to the BeforeSendReply, as the object returned in the former method is passed as the correlationState parameter in the latter. This would be useful if the headers you return are dependent on the headers of the incoming message - as your example suggests.
Finally, to install this functionality on the service, you need to modify the hosting code as follows:
...
var endpoint = serviceHost.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "http://localhost:9000");
endpoint.Behaviors.Add(new ServerInterceptor());
serviceHost.Open();
...
which we can do by virtue of the fact that ServerInterceptor implements IEndpointBehavior