I have been using the Policy Injection Application Block which is new to Enterprise Library 3.0 and continue to be awed by what it and other Aspect-Oriented Programming solutions bring to the development experience. There is something very elegant about moving cross-cutting concerns like logging, caching, exception handling, validation, etc. from code and into meta-data exposed as either declarative attributes or configuration information. It not only removes the clutter to help expose the true intention of our code, but also makes maintaining the code a lot simpler. As with anything you can overuse a good thing to cause an utter maintenance nightmare, but if used appropriately you can gain some cleanliness in your code and improve maintenance.
The Caching Experience
In my web applications, I like to cache the results of expensive calls and use that stale data when appropriate. Not all information needs to be accessible in real-time and can certainly be updated every X minutes without dependencies. This certainly helps with the scalability of your web application. When such simple caching needs are appropriate, the code often follows this simple yet repetitive procedure:
public class Service : IService
{
public Data GetData()
{
// Pre-Processing
Are Results in Cache? If yes, return cached results.
// Real-time Expensive Processing
Nope. Get data from datastore.
// Post-Processing
Cache for X minutes and Return Results.
}
}
The above is intentionally generic, but notice all the clutter with logic about caching. Wouldn't it be nice to just declare the caching via meta-data either through attributes or configuration such that all that exists is just the intention revealing call to the service? I think so...
It makes so much more sense to me to cache behind-the-scenes for such simple caching cases and perhaps just have an attribute that tips us off that caching is indeed happening when we are looking at the code.
public class Service : IService
{
[Cache for 30 minutes]
public Data GetData()
{
Get data from datastore.
}
}
This is exactly what the Policy Injection Application Block provides us as long as we adhere to a few rules. It allows us to avoid this repetitive code for such simple needs and allow us to better understand and maintain our code when the needs of the application change. It essentially intercepts the method call and does the pre-processing and post-processing on our behalf and allows us to just express the code in its purest form without cluttering it with cross-cutting concerns.
The rules are relatively simple. You have to create your services using a factory as opposed to creating them explicitly. Under the covers the Policy Injection Application Block may pass you a proxy class if it finds that you want it to intercept some method calls and do some pre- and post- processing:
IService service = PolicyInjection.Create<Service,IService>();
Using attributes, you can simply express where interception needs to occur by adding an attribute ( CachingCallHandler Attribute for caching ) to a method on the Service Class where you want it to cache on your behalf. Specify the time in hours, minutes, and seconds.
public class Service : IService
{
// hours, minutes, seconds
[CachingCallHandler(0, 30, 0)]
public IList GetData()
{
Get data from datastore.
}
}
Note that the attribute is purely optional and you can specify the caching via a configuration file which gives you a bit more maintenance flexibility without touching code. The lack of an attribute could also be confusing because it is not obvious that caching is actually occuring.
Policy Injection Application Block Tutorials
I talk more about the Policy Injection Application Block in various tutorials:
Please check out all my Enterprise Library 3.0 Tutorials.
by David Hayden