Architecture, WCF Services and Caching

Blog Article

On a recent project we had the requirement to produce a web application as part of the main deliverable, but also to provide a services layer or implementation, that will allow external clients within the same organization to interact with the underlying system.

The underlying system is a combination of SQL data access and web services to other systems. The services provide an aggregated view and usage of the other services and local data to the system.

So the simplified high level concept diagram of the system looks something like this:

Now the ability to allow external systems to access our services are not immediate, but they will be required in further iterations of the product. I originally had a full WCF host exposing the WCF services from which the presentation tier could access, however this proved unwieldy in terms of extra overhead from a configuration and performance perspective. As well as being unnecessary when accessing from the presentation tier and involved an extra worry of flowing identity across the service boundary and attaching to the service thread where it proved no value to do so. However, I love the idea of an explicit boundary for those services, even if we are accessing them directly. So the WCF services are just that. Explicit services defined by interface with proper data contracts and service contracts.

The presentation tier however does not utilize a proxy per se to access them but instead gets a direct reference, however more on that in a second. The external system, when that part of the product iteration is required, can access our services easily as we can host and expose services however we see fit. All access to downstream functionality, whether via presentation tier or external system is done through the service layer, no buts, no maybe's. Its nice and clean.

I am also a big fan of a good caching strategy and in order to do this, with the least amount of effort and greatest flexibility, we did the following:

  • Every service operation is a virtual method.
  • The presentation tier can access its required service via the use of a factory implementation.
  • Depending on configuration, when a service of a specific interface is requested, the factory will return an instance of the service class itself if caching is disabled, or an instance of a class that derives from the service, but overrides the methods that it will provide caching for.

So, a service contract may look like this:

[ServiceContract()]
public interface IService1
{
  [OperationContract]
  string MyOperation1(string arg1,int arg2);
  [OperationContract]
  string MyOperation2(string arg);
  [OperationContract]
  string MyOperation3(DateTime arg);
}

and the corresponding service implementation/operation contract looks like:

public class service1 : IService1
{
  #region IService1 Members

  public virtual string MyOperation1(string arg1, int arg2)
  {
    // do some stuff
    return string.Format("You passed in: {0} and {1}", arg1,arg2);
  }

  public virtual string MyOperation2(string arg)
  {
    // do some stuff
    return string.Format("You passed in: {0}", arg);
  }

  public virtual string MyOperation3(DateTime arg)
  {
    // do some more stuff
    return DateTime.Now.ToShortTimeString();
  }

  #endregion
}

Notice the use of the virtual keyword on the operations.

Those previous 2 code snippets represent blocks from the service layer, where the explicit boundary is set.

In my caching layer which sits above this, my class implementation looks something like this (although this is much simplified):

public class CacheService : service1
{
  public override string MyOperation1(string arg1, int arg2)
  {
    string returnData = GetValueFromCache(arg1, arg2);
    if (string.IsNullOrEmpty(returnData))
    {

      // Data is not in the cache, so call our actual service
      // to get the data and add it to the cache again.

      returnData = base.MyOperation1(arg1, arg2);
      AddToCache(returnData);
    }

    return returnData;
  }
}

You will notice that the CacheService class only overrides the MyOperation1 method, and does not override MyOperation2 or MyOperation3. So caching functionality is only performed for MyOperation1. The other methods do not need to be implemented as the class inherits them anyway. So basically, I only override the methods that I want to provide caching functionality for, and disregard the other methods. I call down to the base class method to actually retrieve the data when required. I don't have to do anything special or duplicate any code AND this class still honors the interface, which means my factory can return this 'caching' class or the actual service class, the client never knows or cares. It just wants an implementation of the service contract and goes about getting it like this:

IService1 myservice = MyFactory<IService1>.GetInstance();

In the examples provided above, if caching were enabled, you'd get an instance of CacheService class. If caching was disabled, you'd get an instance of the service1 class. With caching enabled, I check individual cache durations, and inject cache dependencies for various method calls where it makes sense for our data. For example, when I retrieve a list, I add it to the cache, and also attach a cache dependency. Whenever another method, adds, deletes, updates something related to the list. I just delete the cache dependency, causing all dependents to be flushed, and repopulated in the cache on the next call.

To fully implement all my services in this higher level caching layer even for those that wont be using caching, I just do something like:

public class CacheService : service1 {}

As you can see, no implementation. The base class takes care of that for me. so my factory can return an instance of this class if caching is enabled, but not strictly provided for this class. Later, its easy to just override a method and provide some caching semantics if required.

So the new concept diagram looks like this:

So in summary:

  • The application provides an explicit boundary around its services allowing external clients access via standard WCF mechanisms.
  • The presentation tier has direct access to the services but only access them via the interface.
  • A factory  provides an instance of the service requested, as designated by the interface, depending on whether caching is enabled or not.
  • Caching is easily implemented by overriding the virtual service method and providing only caching semantics, calling down to base services for actual data where required.
  • Caching support becomes really easy.
  • The factory design will allow a proper WCF proxy to be returned if we ever need to separate the presentation and services by a physical boundary (although not required now or in the immediate future)

Hope that's interesting for you. It is working very well in the current project, is clean, easy to understand, and easy to implement. It neatly separates out caching concerns from the logic that provides the actual data, and provides a very clean and explicit boundary for the services themselves allowing a good degree of flexibility.

6 Comments

  • Hi Pablo, thanks for your comments. I can't say I have played much with the policy injection block but on the surface it does seem a good fit. In my specific scenario, some of the scenarios are quite different from a caching needs perspective and it seemed easier to implement specifically wat was needed at the time. A generic solution as you suggest does seem attractive though. I'd be interested to hear more on it.

  • stevensrf1@inbox.com
    Is there any way to use WCF to download files from a server using secure ftp and sercure http/

  • Hi Glav,
    We have simmilar situation.I have 2 questions here.

    1.How is the Presentation layer is interacting with WCF?Is it directly referencing caching dlls which inter call service methods or is using TCP protocol?

    2.In WCF layer do you have class structure simmilar to domain objects?I mean diffrent interfaces and classes each domain objects?

  • Rajeev,

    The presentation interacts directly with the WCF endpoints through interface only, not via an actual WCF pipeline, however it is written as a WCF like service to make it very easy to expose when required.

    To answer your 2nd question, the WCF layer is very message oriented and bears almost no resemblance to the domain model (although there are some similarities). The domain model is quite granular, the WCF layer uses an aggregate request and response object that holds the required information and is very carefully designed from a serialisation point of view and contextual data point of view.

  • Hi Glav,

    I'd be very interested in the source code of your channel factory. Is there any way you can publish it ? Thanks

  • I really like this was of doing caching. Any chance of us having a peek at your channel factory ?

Comments have been disabled for this content.