Part 1: The client setup
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.
In the previous post, I configured the client to write a header on any outgoing request if a specified cookie was found. I knew I could look for that header easily, but I had to find a way to change the behavior of a given operation.
I spent a while searching around for something that would let me do this, but I couldn’t find anything that would let me inject new type over an existing on a per-call basis. It may be that something like Ninject would have done this, but from what I understand (having never used it) it would replace all instances of a given type with a new one, not targeted instances. If I am wrong, please let me know.
Lucky for me, we had a nice little pattern going in our code. Each service was just a shell to call out into an appropriate controller, and the controller had all the meat and potatos. For example:
public class MyService : IMySerivce
{
public void DoSomeWork()
{
MyServiceController controller = new MyServiceController();
controller.DoSomething();
}
}
I extended this by creating a custom ServiceBase class that any WCF service we wanted to be mockable would inherit from. It provided a single item. (There was also a base that all of our controllers were to inherit from.)
public class AppBaseService
{
protected ITypeFactory typeFactory=new DefaultTypeFactory();
public virtual ITypeFactory TypeFactory
{
get { return this.typeFactory; }
set { this.typeFactory= value; }
}
}
public class ControllerBase
{
protected ITypeFactory typeFactory;
public ControllerBase(ITypeFactory typeFactory)
{
this.typeFactory= typeFactory;
}
}
Now is a good time to note that the DefaultTypeFactory just newed up whatever type you provided it.
So, with these changes any service that was to be mockable would look something like this:
public class MyService : ServiceBase, IMySerivce
{
public void DoSomeWork()
{
MyServiceController controller = new MyServiceController(this.TypeFactory);
controller.DoSomething();
}
}
//and the inners of the controller looked like:
public class MyServiceController : ControllerBase
{
public MyServiceController(ITypeFactory typeFactory)
{
this.typeFactory = typeFactory;
}
public void DoSomething()
{
IDataAccessClass dataAccess = this.typeFactory.CreateType(typeof(MyConcreteDataClass)) as IDataAccessClass
dataAccess.ExecuteSomething();
}
}
This allowed me to set whatever ITypeFactory I want on a per call basis. Like I said above, the default one would just new up whatever type you gave it, but I could easily create one that would return a new type based on whatever you asked for. So in the example above, instead of returning a new MyConcreteDataClass, I could return a MyMockedDataClass (assuming that implement IDataAccessClass, of course!)
With the grunt work out of the way, part 3 will be the WCF extensions that tied all this together.
short link to this post:
wcf, asp.net, Fun with .net
webdev, programming