Modifying a WCF operation at runtime – part 1

4. July 2010

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


short link to this post:

wcf, asp.net, Fun with .net ,

Add comment


(Will show your Gravatar icon)

biuquote
  • Comment
  • Preview
Loading