Jul
4
2010

Modifying a WCF operation at runtime – part 1

I started to make this one big post, but it was a lot of information to try to pack into something readable. So I decided to split it up.

While at work the other day I was talking to my boss, and the subject of spoofing data came up. He mentioned that for our current project, it would be nice to be able to spoof data on a per-request basis. I thought it would be a fun challenge to tackle, so I spent a few hours last Saturday and came up with a pretty elegant solution.

Before I started, I had a few requirements:

  • It had to be completely config driven. The client and target WCF service were to have no idea what was going on.
  • It was to be on a per-user/per-request basis. What this means is any dev could turn it on/off and it would only affect him.
  • Extensible. If you didn’t like the data I mocked, or needed to be able to simulate slow network traffic, exceptions, large data, etc - you could.
  • I only had 5 hours to come up with a solution.

 

The concept I was striving for was being able to write a cookie or add a query string to your request, and be served up mock data instead of live data from dev. Previous to this, I hadn’t played with extending WCF very much, but it turns out everything was quite simple. I started by implementing an IClientMessageInspector. It had one job. Inspect every outgoing request, and add an additional header if the appropriate cookie/querystring was found.

public class MockClientMessageInspector : IClientMessageInspector
{
    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        //check for the cookie/querystring 
        bool shouldMock = ...;

        if (shouldMock) 
        {
            request.Headers.Add(MessageHeader.CreateHeader("mockdata", "ns", true));
        }
        return null;
    }
}

 

To add this behavior to the client, I implemented an IEndpointBehavior, and a BehaviorExtensionElement to go with it.

public class MockClientEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

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

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

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    protected override object CreateBehavior()
    {
        return new MockClientEndpointBehavior();
    }

    public override Type BehaviorType
    {
        get
        {
            return typeof(MockClientEndpointBehavior);
        }
    }
}

 

Now all the client has to do is add the correct config entries, and he is all ready to go. Want to remove the capability? Remove the configuration. It is that simple.

<system.serviceModel>
  <extensions>
    <behaviorExtensions>
      <add name="mockClientInspector" type="ServiceMocker.MockClientEndpointBehavior, ServiceMocker" />
    </behaviorExtensions>
  </extensions>

  <behaviors>
    <endpointBehaviors>
      <behavior name="MyBehaviorConfig">
        <mockClientInspector/>
      </behavior>
    </endpointBehaviors>
  </behaviors>

  <client>
    <endpoint
           address="..."
           behaviorConfiguration="MyBehaviorConfig"
           binding="basicHttpBinding"
           bindingConfiguration="..."
           contract="..."
           name="..." />
  </client>
</system.serviceModel>

 

Stay tuned for part 2 where I will talk about what happens in the service

Add comment




biuquote
Loading


AdSense

Software engineer by hobby and trade. When I am not sitting in front of a computer, you can find me playing with my kids. I am lucky enough to be married to my best friend and high school sweetheart. Life couldn't be better!

 

All content is mine, not my employers

Chronology

Tweets

what is the easiest way to *just* the last changeset number from git?
21 hours ago via Silver Bird
@ParasValecha so it is a virus some marketing guy manage to win an award for? ;)
3 days ago via Silver Bird
@ParasValecha none. I think they are one of the worse "viruses" you can get. Thrashing your disk and hogging CPU any chance they get
3 days ago via Silver Bird
...i have gone 5 years without one and been fine
3 days ago via Microsoft
... and provide little value on a day to day basis. Don't go to random content, and don't open stuff you don't understand...
3 days ago via Microsoft
I wholeheartedly believe that virus scanners are one of the worst things to install. they really slow down your computer...
3 days ago via Microsoft
RT @CodeWisdom: "When your hammer is C++, everything begins to look like a thumb." - Steve Haflich #fb
5 days ago via rowi for Windows Phone
Follow me on Twitter