I frequently get asked how to add a header to every outgoing request so I wrote up a quick reusable approach. This adds some extension methods to the IContextChannel class for working with auto-added headers. The headers are stored between calls in an IExtension.
public static class AutoHeaderExtension{ class AutoHeaderContextExtension : Dictionary<XName, MessageHeader>, IExtension<IContextChannel> { public void Attach(IContextChannel owner) { } public void Detach(IContextChannel owner) { } } public static void AddAutoHeader(this IContextChannel proxy, string name, string ns, object value) { AutoHeaderContextExtension extension = proxy.Extensions.Find<AutoHeaderContextExtension>(); if (extension == null) { extension = new AutoHeaderContextExtension(); proxy.Extensions.Add(extension); } extension[XName.Get(name, ns)] = MessageHeader.CreateHeader(name, ns, value); } public static IEnumerable<MessageHeader> GetAutoHeaders(this IContextChannel proxy) { AutoHeaderContextExtension extension = proxy.Extensions.Find<AutoHeaderContextExtension>(); if (extension == null) { return Enumerable.Empty<MessageHeader>(); } return extension.Values; } public static void RemoveAutoHeader(this IContextChannel proxy, string name, string ns) { AutoHeaderContextExtension extension = proxy.Extensions.Find<AutoHeaderContextExtension>(); if (extension != null) { extension.Remove(XName.Get(name, ns)); } }}
If you combine that with a message inspector that adds the headers on to each message, then you get a collection of headers that are added to every outgoing request.
public class AutoHeaderMessageInspectorBehavior : IEndpointBehavior{ class AutoHeaderMessageInspector : IClientMessageInspector { public void AfterReceiveReply(ref Message reply, object correlationState) { } public object BeforeSendRequest(ref Message request, IClientChannel channel) { foreach (MessageHeader header in channel.GetAutoHeaders()) { request.Headers.Add(header); } return null; } } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new AutoHeaderMessageInspector()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { }}
Here's an example using this extension.
[ServiceContract]public interface IService{ [OperationContract(Action="*")] void Test();}public class Service : IService{ public void Test() { Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage); }}class Program{ static void Main(string[] args) { string address = "http://localhost:8000/"; Binding binding = new BasicHttpBinding(); ServiceHost host = new ServiceHost(typeof(Service), new Uri(address)); host.AddServiceEndpoint(typeof(IService), binding, ""); host.Open(); ChannelFactory<IService> factory = new ChannelFactory<IService>(binding); factory.Endpoint.Behaviors.Add(new AutoHeaderMessageInspectorBehavior()); factory.Open(); IService proxy = factory.CreateChannel(new EndpointAddress(address)); proxy.Test(); ((IContextChannel)proxy).AddAutoHeader("TestHeader1", "http://test", "test1"); proxy.Test(); ((IContextChannel)proxy).AddAutoHeader("TestHeader2", "http://test", "test2"); proxy.Test(); proxy.Test(); ((IContextChannel)proxy).RemoveAutoHeader("TestHeader1", "http://test"); proxy.Test(); factory.Close(); host.Close(); Console.ReadLine(); }}
Next time: Pipe Properties
How do I deliver content from a WCF service as part of a web page? Web page content in this case typically