Paulo Morgado

.NET Development & Architecture

This Blog

Syndication

Search

Tags

News

Unit Test Today! Get Typemock Isolator!

Projects

Books

 

Visitors

Visitor Locations

Community

Email Notifications

Archives

Profile

Disclaimer

The opinions and viewpoints expressed in this site are mine and do not necessarily reflect those of Microsoft, my employer or any community that I belong to. Any code or opinions are offered as is. Products or services mentioned are purchased by me, made available to me by my employer or the manufacturer/vendor which doesn't influence my opinion in any way.

WCF: Building an HTTP User Agent Message Inspector

Yesterday I had to build a custom message encoder to be able to call a legacy POX service with iso-8859-1 encoding.

It turned out that the service had another surprise to me: it needs an HTTP user-agent header.

It's something quite simple to accomplish with WCF. All it's needed is to add the required header to the HTTP request message property of the request message. Something like this:

HttpRequestMessageProperty httpRequestMessage = new HttpRequestMessageProperty();

httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);

requestMessage.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);

But I was not willing to pollute my code with this and, besides that, it doesn't look much WCFish having to do this.

Since I don't like to spend too much time trying to figure things out when I know someone who knows it, I asked António Cruz what to do. And the answer was a client message inspector.

With the help of a sample I have built an HTTP user agent client message inspector.

Message Inspector

The message inspector is very simple. We just need to implement the IClientMessageInspector Interface.

public class HttpUserAgentMessageInspector : IClientMessageInspector

{

    private const string USER_AGENT_HTTP_HEADER = "user-agent";

 

    private string m_userAgent;

 

    public HttpUserAgentMessageInspector(string userAgent)

    {

        this.m_userAgent = userAgent;

    }

 

    #region IClientMessageInspector Members

 

    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)

    {

    }

 

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)

    {

        HttpRequestMessageProperty httpRequestMessage;

        object httpRequestMessageObject;

        if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))

        {

            httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;

            if (string.IsNullOrEmpty(httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER]))

            {

                httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER] = this.m_userAgent;

            }

        }

        else

        {

            httpRequestMessage = new HttpRequestMessageProperty();

            httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);

            request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);

        }

        return null;

    }

 

    #endregion

Behavior

But this message inspectors are extensions to the client runtime. Such extensions are configured using behaviors. A behavior is a class that changes the behavior of the service model runtime by changing the default configuration or adding extensions (such as message inspectors) to it.

The implementation of a behavior is, also, very simple. We just need to implement the IEndpointBehavior Interface. In this case, since it's a client message inspector only, all we need to implement is the ApplyClientBehavior method.

public class HttpUserAgentEndpointBehavior : IEndpointBehavior

{

    private string m_userAgent;

 

    public HttpUserAgentEndpointBehavior(string userAgent)

    {

        this.m_userAgent = userAgent;

    }

 

    #region IEndpointBehavior Members

 

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)

    {

    }

 

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

    {

        HttpUserAgentMessageInspector inspector = new HttpUserAgentMessageInspector(this.m_userAgent);

        clientRuntime.MessageInspectors.Add(inspector);

    }

 

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

    {

    }

 

    public void Validate(ServiceEndpoint endpoint)

    {

    }

 

    #endregion

}

Adding the Message Inspector through Configuration

For configuring an endpoint in the application configuration file to use our custom behavior, the service model requires us to create a configuration extension element represented by a class derived from BehaviorExtensionElement.

public class HttpUserAgentBehaviorExtensionElement : BehaviorExtensionElement

{

    public override Type BehaviorType

    {

        get

        {

            return typeof(HttpUserAgentEndpointBehavior);

        }

    }

 

    protected override object CreateBehavior()

    {

        return new HttpUserAgentEndpointBehavior(UserAgent);

    }

 

    [ConfigurationProperty("userAgent", IsRequired = true)]

    public string UserAgent

    {

        get { return (string)base["userAgent"]; }

        set { base["userAgent"] = value; }

    }

}

This extension must then be added to the service model's configuration section for extensions:

<system.serviceModel>

...

  <extensions>

    <behaviorExtensions>

      <add name="httpUserAgent" type="Pajocomo.ServiceModel.Dispatcher.HttpUserAgentBehaviorExtensionElement, Esi.ServiceModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

    </behaviorExtensions>

  </extensions>

...

</system.serviceModel>

Note: We must use the full assembly qualified name here, otherwise it won't work.

Now we need to apply our behavior extension to a behavior configuration:

<system.serviceModel>

...

  <behaviors>

    <endpointBehaviors>

      <behavior name="LegacyServiceEndpointBehavior">

        <httpUserAgent userAgent="test user agent" />

      </behavior>

    </endpointBehaviors>

  </behaviors>

...

</system.serviceModel>

Adding the configuration to the service configuration

Now we can apply this configuration to our sevice configuration:

<system.serviceModel>

...

  <client>

    <endpoint

      address="..."

      binding="..."

      bindingConfiguration="..."

      behaviorConfiguration="LegacyServiceEndpointBehavior"

      contract="..."

      name="..." />

  </client>

...

</system.serviceModel>

And we are all set to go.

Published Fri, Apr 27 2007 0:50 by Paulo Morgado

Comments

# re: WCF: Building an HTTP User Agent Message Inspector@ Sunday, September 16, 2007 11:44 PM

Hi,

I used the same method as you specified in this post, to add some custom HTTP headers. But there seems to be some kind of timing issue in the headers reaching the server. The headers don't reach the server on time always. So my program works when I run it in a debugger but does not work otherwise.

Do you have any ideas on how I could fix this?

Thanks

-Rama

Rama

# re: WCF: Building an HTTP User Agent Message Inspector@ Monday, September 17, 2007 5:15 PM

Hi Rama,

There must be something else there.

If the body of the HTTP request gets to the server, the HTTP headers must get ther first.

Have you tried to use something like the Fiddler tool to see what's going on the wire?

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Friday, July 25, 2008 10:22 AM

what i need to do is, valid the input against the data contract i have. Do you think this will be useful?

saudamini

# re: WCF: Building an HTTP User Agent Message Inspector@ Friday, July 25, 2008 10:27 AM

How do i test this?

saudamini

# re: WCF: Building an HTTP User Agent Message Inspector@ Saturday, July 26, 2008 12:22 PM

@saudamini

What exactly do you want to validate? Have looked at the Validation Application Block in the Entreprise Library? There's an implementation to validate data contracts.

One way to test this is having a proxy like Fiddler and look at the HTTP payload.

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Wednesday, December 03, 2008 9:55 AM

I know this post is a bit old, but I wanted to point something out.  One thing that I keep seeing with message inspectors.  Using the setup you described you end up having to create multiple classes in order to do one thing.  Only one of those classes derives from a base, the rest simply implement interfaces.  So why don't you just do the following?

HttpUserAgentEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior, IClientMessageInspector

Then you can have 1 class that performs all the tasks that you need.

Chris

# re: WCF: Building an HTTP User Agent Message Inspector@ Wednesday, December 03, 2008 6:48 PM

Hi Chris,

It has been some time since I plyed with this and I made it from a sample.

I don't really know what is the instance creation ratio and if there are threading issues.

Have you tried it?

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Tuesday, February 17, 2009 3:55 PM

Thank you for your post. It works!

Sergey Kostrukov

# re: WCF: Building an HTTP User Agent Message Inspector@ Tuesday, February 17, 2009 5:02 PM

Always glad to help.

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Wednesday, May 19, 2010 1:26 PM

How do i test this samle?

vaibhavs

# re: WCF: Building an HTTP User Agent Message Inspector@ Wednesday, May 19, 2010 6:30 PM

Well, vaibhavs.

I don't think I understand what you are asking for.

When I developed this, the service I was calling simply answered wtih a 500 HTTP status if I didn't use this.

If you want to inspect the HTTP payload, I suggest using something like Fiddler.

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Wednesday, December 29, 2010 12:28 AM

Hi Paulo Morgado,

Your article is so helpful. i am able to send the header info to the service and able to read the header information too.Now i want to send this header information to another service header. is there any best practices can you suggest me?

give me your ideas.

thanks

Ibrahim.(IND)

Ibrahim

# re: WCF: Building an HTTP User Agent Message Inspector@ Wednesday, March 16, 2011 8:56 AM

I tried the above steps but the custome header was not there in the request message. I could check this using Fiddler. Breakpoints are hit at the implemented methods. Any idea?

Bruce

# re: WCF: Building an HTTP User Agent Message Inspector@ Wednesday, March 16, 2011 8:51 PM

I haven't touched this in a while, but it worked at the time.

What version of the framework are you using?

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Saturday, April 16, 2011 5:17 AM

Hi ,

I also tried this in the WCF routing service i i have added the custom header but in the WCF service side i am unable to get this.

any idea?

Vivek

# re: WCF: Building an HTTP User Agent Message Inspector@ Sunday, April 17, 2011 7:10 PM

Have you tried to use Fiddler (or similar) to see where the header was lost?

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Tuesday, February 21, 2012 6:29 AM

Wow! Thanks for this wonderful post.

Abhilash

# WCF HTTP User Agent Message Adapter On GitHub And Nuget@ Sunday, June 10, 2012 8:22 PM

Some time ago, I wrote about building an HTTP user agent message adapter for WCF . Now, Henk J MeuleKamp

Paulo Morgado

# WCF HTTP User Agent Message Adapter On GitHub And Nuget@ Sunday, June 10, 2012 8:22 PM

Some time ago, I wrote about building an HTTP user agent message adapter for WCF . Now, Henk J MeuleKamp

Paulo Morgado

# re: WCF: Building an HTTP User Agent Message Inspector@ Monday, June 18, 2012 5:17 PM

This worked very well for me, thank you!

A few years ago Chris suggested just implementing a single class: HttpUserAgentEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior, IClientMessageInspector

I followed this approach and with some small tweaks it worked brilliantly.

Stefan Mohr

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above: