Friday, February 5, 2010

WCF Design Pattern: Generic Service

WCF provides great opportunities to architects for building robust applications. One thing many architects may not realize is that it is also a great technology for building reusable patterns as well; and to do so without incurring limits on the types of entities and fields operated on by the service.

A common task is to create an SOA that provides business rules in a WCF Facade that also calls into an abstracted data storage mechanism. This data storage can vary from service to service depending on the originating source for the data that the Facade is exposing as a service. Although it is very easy to create this pattern, it's not usually intuitive to do so in a generic manner; but since you're reading this you know I have a pattern in hand that fits the bill!

The WCF Generic Service Pattern has three parts: the service facade, business entity (or entities) and business entity persistence. To create a reusable pattern, we start with our entity as an abstract base class:

public abstract class EntityBase
{
Key m_keyID;

[DataMember]
public Key ID
{
get { return m_keyID; }
set { m_keyID = value; }
}
}
This looks like Generics 101, right? Just a simple entity with a definable key. What could be easier? Well, when we create our concrete entity all we need to do is supply a type for the key!

[DataContract]
public class Entity : EntityBase
{
// Nothing needed!
}
OK, nothing is needed to support using a GUID for the value of the ID property. But this is a WCF article, so you should note a couple of things. First, DataContract and DataMember are not married to each other. I've defined a DataMember in the abstract EntityBase, but it is not a DataContract; which it couldn't be because you cannot instantiate EntityBase. The Entity class is what's marked as a DataContract and the base class members marked as DataMember will be serialized by WCF.

So, we've created our Entity, so how are we going to save it to the database? Well, not only are we abstracting details about the entity, we are also abstracting details about persistence. What if one entity required saving to XML while another required saving to Oracle? It's as easy as spelling interface!

public interface IEntityPersistence
{
TEntity GetByKey(Key key);
}
Hmm, see the generics on the Interface? This is the meat-and-potatoes of this design pattern which allows any number of implementations to be created to work with the entities of your choice. To handle our previously defined entity, the persistence class looks like this:

public class Persistence : IEntityPersistence
{
#region IEntityPersistence Members

public Entity GetByKey(Guid key)
{
// TODO: Implement your data access code here!
throw new Exception(
"The method or operation is not implemented.");
}

#endregion
}
Note that the class declaration sets the persistence provider to use our Entity class with a Guid for the key. You'll need to handle the actual persistence here.

OK, we have our entity and our persistence, now let's expose them as a service! Best practices for WCF say to use an interface for our service's ServiceContract:

[ServiceContract()]
public interface IService
{
[OperationContract]
TEntity GetByKey(Key key);
}
Here we define both the WCF ServiceContract and the OperationContract for GetByKey. Notice the use of generics; we are once again making our service pattern completely reusable. Next, we create an abstract service base class that has our reusable functionality:

public abstract class ServiceBase : IService
{
protected IEntityPersistence m_objPersistence = null;

#region IService Members

public TEntity GetByKey(Key key)
{
return m_objPersistence.GetByKey(key);
}

#endregion
}
This easy! We've declare an instance variable to hold our persistence instance and actually used it to return our entity from our data store. What's missing? Oh, yeah, the instantiation of the persistence class! Now we need to provide an actual public class that WCF can instantiate:

public class Service : ServiceBase
{
// This constructor sets the appropriate
// persistence instance for the entity
// being exposed by this service.
public Service()
{
m_objPersistence = new Persistence();
}

// All the business rules for the entity
// is handled in the ServiceBase class!
}
And that's it! We now have a complete WCF service build from our WCF Generic Service pattern. We could create any number of sub-classes of EntityBase and matching facade and persistence classes. This is a very powerful tool for creating a consistent API with WCF.

No comments:

Post a Comment