Using generics to reuse code for WCF services
I’m definitely a sucker for code reuse (as I’d argue all programmers should be).
If you’ve had experience working with setting up WCF services for run-of-the-mill CRUD operations (i.e. adding new entities, getting entities, etc), you know how much of a pain in the behind it is to manually type out code designed to work with a single, specific entity (or aggregate). If you’ve got ten entity types available across your SOA, then you might expect to write at least a service operation tailored for each of them, for each of your CRUD processes.
That’s, in and out of itself, 40 operations that more or less will use the same gist of code.
Reusing CRUD code in WCF services
While your mileage may vary (and in real-life projects, the exact same code across all your operations is significantly unlikely), I’ve had to work with this exact situation a few weeks back (spewing out a Stack Overflow entry in the process) and the eventual solution is spiffy enough not to share.
For a good amount of the time, reusing code just means inheriting a base class, however, in the case of service operations, we can’t tag generic methods / classes (which we really want to use as a base class) as service contracts.
A great workaround, is to utilize three things in writing out your operations: an interface for the contract, a (abstract) base class for the generic methods, and another class to function as the tangible service endpoint.
[ServiceContract] public interface IPersonServiceContract { [OperationContract] void Add(Person person); [OperationContract] Person Get(int id); } |
// Entity is our POCO entity base class public abstract class GenericCrudService<T> where T : Entity { // assuming Entity Framework 4.1 CF public void Add(T entity) { context.Set<T>().Add(entity); context.SaveChanges(); } public T Get(int id) { return context.Set<T>().Where(x => x.Id == id).FirstOrDefault(); } } |
// and this will serve as the actual endpoint public class PersonService : GenericCrudService<Person>, IPersonServiceContract { // no code necessary } |
It’s pretty handy, if you ask me. For all additional endpoints you have to create, all you have to do is write out the service contract via an interface, create the actual endpoint, and have it inherit from the contract and the GenericCrudService using the specific type you need.
Discussion