WCF Custom Headers: A Short How-To

Recently I was working on a project that entailed a web application that called into a back end WCF service. That WCF service was connected to a system for which the users of the web application were not known as users due to licensing issues, so the calls were made under the credentials of a service account. However, the back end system did have access to some information on the users of the web application and needed to make some authorization decisions based on that information. So I needed to make the username of the web user known to the back end WCF service, even though the call takes place under different credentials.

The solution to these types of requirements is usually a custom header, so that’s the approach I took. However, I did not want the developers to be required to manually modify every service proxy they create. Moreover, adding the header in code just does not seem as clean as it can be. So I decided to create message inspectors to handle the application of the headers, and let custom behaviors be responsible for applying the message inspectors. The behaviors can then be applied to both the WCF service and the client though the config files. I will go through these steps in this post, but if you just want a working sample, the sources are available here.

The Header

First off, I created a custom header that derives from MessageHeader.

    public class UsernameHeader : MessageHeader
    {
        public const string UserAttribute = "userName";

        public const string MessageHeaderName = "UserName";

        public const string MessageHeaderNamespace = "http://wcfheaderbehavior.com/services/username";

        public string UserName { get; private set; }

        public UsernameHeader(string userName)
        {
            if (String.IsNullOrEmpty(userName))
                throw new ArgumentNullException("userName");
            UserName = userName;
        }

        public override string Name
        {
            get { return MessageHeaderName; }
        }

        public override string Namespace
        {
            get { return MessageHeaderNamespace; }
        }

        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteAttributeString(UserAttribute, UserName);
        }
    }

Of course I could have opted for an untyped header that would have slightly simplified extracting it from the request, but this gives more flexibility in case it’s not just a single value that needs to be transmitted.

The Client

The next step is to create the client part of the solution. For the message inspector, we need to create a class that overrides IClientMessageInspector. The method implementations look like this:

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            // TODO: fill the header below with the user name from the current thread, for example
            var header = new UsernameHeader("UserName");
            request.Headers.Add(header);

            return null;
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
        }

As this implementation shows, I only need to handle the BeforeSendRequest method, because I only have to do something upon sending a request; not while receiving a response. In the BeforeSendRequest implementation, I simply create the UserNameHeader and initialize it with the username, and add it to the request headers.

Now I want to create a behavior that applies this message inspector to the runtime. This can be done by implementing IEndpointBehavior. Since both IEndpointBehavior and IClientMessageInspector are just interfaces (as opposed to base classes), I can use my existing class to implement this second interface. The implementation looks like this:

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

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

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

The only method with an actual implementation is ApplyClientBehavior, which adds the instance (i.e. the IClientMessageInspector implementation) to the collection of message inspectors of the passed in ClientRuntime.

All that’s left to do for the client behavior is to implement BehaviorExtensionElement so as to be able to add the behavior to the client through the config file. And since this is the only class we need to implement for our solution, we can use the same class that already implements the two interfaces. The implementation of BehaviorExtensionElement looks like this:

        protected override object CreateBehavior()
        {
            return this;
        }

        public override Type BehaviorType
        {
            get { return GetType(); }
        }

The Service

Now for the service side. We basically do the same thing as we did with the client, the only difference being in the interfaces to implement. Because we want to modify the service runtime now, we implement IDispatchMessageInspector instead of IClientMessageInspector. The implementation looks like this:

        public UsernameHeader UsernameHeader { get; private set; }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            var headerIndex = request.Headers.FindHeader(UsernameHeader.MessageHeaderName, UsernameHeader.MessageHeaderNamespace);
            if (headerIndex >= 0)
            {
                var reader = request.Headers.GetReaderAtHeader(headerIndex);
                UsernameHeader = ParseHeader(reader);
            }

            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }

        private static UsernameHeader ParseHeader(XmlDictionaryReader reader)
        {
            if (reader.IsStartElement(UsernameHeader.MessageHeaderName, UsernameHeader.MessageHeaderNamespace))
            {
                var originatingUser = reader.GetAttribute(UsernameHeader.UserAttribute);
                if (String.IsNullOrEmpty(originatingUser))
                {
                    throw new FaultException("No originating user provided", FaultCode.CreateSenderFaultCode(new FaultCode("ParseHeader")));
                }

                return new UsernameHeader(originatingUser);
            }

            return null;
        }

What this does upon receiving a request is parse out the UsernameHeader and set it to a property. This way, the deserialized header becomes availabe for user code as a property of the service behavior because we will implement the behavior and the message inspector in the same class, just like we did with the client. Again, I could have opted for a simpler approach that involves extracting the header directly from the OperationContext when needed. Going through the extra step of accessing it through the behavior, however, is a cleaner approach. First of all I just need to extract the header once, but more importantly this approach conforms to the general idea of the behavior as the primary WCF extension and interaction point.

Now the interface we implement for the behavior is IServiceBehavior. This differs slightly from the IEndpointBehavior interface, which can be an alternative in some scenarios. The implementation is, again, very simple:

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
            {
                foreach (var endpointDispatcher in channelDispatcher.Endpoints)
                {
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
                }
            }
        }

What we do here is apply the instance (i.e. the IDispatchMessageInspector) to all endpoints. And just as with the client, we have our class inherit from the BehaviorExtensionElement so as to make it configurable through the config file.

Connecting The Dots

Now all that’s left to do is modify the config files to make all this work. For both the client and the service, we need to register the custom BehaviorExtensionElement like this:

<system.serviceModel>
  <extensions>
    <behaviorExtensions>
      <add name="UsernameBehavior" type="[Fully qualified assembly name of wither the client or the service behavior]" />
    </behaviorExtensions>
  </extensions>
</system.serviceModel>

Then, we need to register the behavior for the client:

<system.serviceModel>
    <client>
        <endpoint behaviorConfiguration="ClientBehavior" />
    </client>
  <behaviors>
    <endpointBehaviors>
      <behavior name="ClientBehavior">
        <UsernameBehavior />
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>

And the service:

<behaviors>
  <serviceBehaviors>
    <behavior>
      <UsernameBehavior/>
    </behavior>
  </serviceBehaviors>
</behaviors>

To actually get the value from the header, simply extract the behavior from the OperationContext:

            if (OperationContext.Current != null)
            {
                var usernameBehavior = OperationContext.Current.Host.Description.Behaviors.Find<UsernameServiceBehavior>();
                if (usernameBehavior != null && usernameBehavior.UsernameHeader != null)
                {
                    return usernameBehavior.UsernameHeader.UserName;
                }
            }
            return null;

And that’s it! Hope this helps. Full source code is available here.

UPDATE: I added a small code snippet that shows how to actually access the header on the service side. I also elaborated a bit on the reasoning behind the approach of making the header available through the service behavior instead of accessing it directly.

Advertisement