Taking a break from my "results oriented theory"...
I like services, I like the ability to call the same API’s remotely as I would call inside a website that I develop. The issue I have with this is overhead. And not just service call overhead, there is configuration overhead, debugging overhead and a slew of little things that all have to be aligned in order for things to work right.
Add on top of that I end up doing double duty. I hit the database to load up a context with items I expect to work with, then pass those items to a service which has to requery the same objects back out to do their work. Considering my web server is only 1 hop away from my database this seems pointless.
So what I want, is a way to construct a class that can be used like a the service would when it is constructed as a local heap object, and also use that same class to run as a service. Depending on how the class is hosted it changes some of its functionality. Take this simple service interface.
And the implementation
Notice the empty constructor is “protected”, WCF can use the protected constructor when instantiating this as a service, however our web code will use the constructor with the “context” parameter passing in our database context.
And now we see the problem. The service based instance won’t have a database context to run against. FindUserByUserId will fail with a NullReferenceException.
We could just construct the Context in the constructor, but what fun is that. So what we need is a way to wrap our service calls. For starters I have the CreateServiceContext() call, this is where you put your creation logic for a service call. Its wrapped in an IDisposable so all your cleanup will occur at the end of the method call. So for my service calls I implement an Invoke on the base using a delegate to call the original method on the class.
I have a HandleServiceException virtual method in case I want to custom wrap exceptions. Lets say I want to throw an ArgumentException when the method is invoked in web code, but I want that wrapped into an FaultException<ArgumentFault> in the service. I would put that code in the HandleServiceException.
Now, to implement the service interface explicitly and forward the calls through the invoke.
And there we have it, a service class that is context bound when running from the heap, yet single-call when running in a service host.
Now to move a step beyond, we may need to change the way the service works based on parameters. Inside the service hosted environment we will expect the user to provide scope parameters. While being called as a local heap object we can provide those parameters as part of the construction of the object.
The class implementation
In this service we expect to only operate on a single platform level. From a service call we must determine that context from the method call, from the web code we know that earlier and sending it in via the constructor is more prudent.
The ValidatePlatform() is invoked in methods that we want to ensure we have a platform bound before we begin our work.
Now for the service interface
And the service interface implementation
Notice the platformId is sent in via the method call. This scoping parameter gets converted to the service property in the explicit interface implementation.
I’ve been using this technique for a few months now on my services. And it has been pretty slick. The composition capabilities of my services is insane, but I’ll save that for a future article.
Another bonus of this technique is testing. Since the core of the service gets exercised both through the testing of our app via WCF and through direct invocation from the websites.
Find it in Source Code –> Browse –> trunk/Samples/ServiceObjects