If you're an ASP.NET programmer and have never heard of those terms, they're basically the same as the Container or Provider pattern (provider pattern is issued by MS in ASP.NET 2.0 for Profiles, Membership, Roles, Session storage etc...).
Lately I've had 2 use cases that fit this need perfectly. I downloaded Castle.Windsor and started digging into it.
Sample Scenario: caching.
Every ASP.NET programmer has used ASP.NET's static Cache. It's fast, easy to implement, until... you try running it in a web farm. .Net doesn't support distributed caching out of the box, ,o now you're stuck with a bunch or redundant caches on each server that get out of sync easily. If you use SQL Server 2005, you can try using SQL Dependencies. I did. It started generating a whole bunch of events in the event log, and was overall not very reliable. Not only that, but now you've built a system that's highly reliant on a SQL Server 2005 backend. What if you decide using MySQL? Then ASP.NET will poll the database, and you're going to have more scalability issues.
Here comes distributed caching. Basically your cache is now located on a cluster of caching server shared among your web front-end servers, and now you only need to worry about that one cache being in sync with the database. There are different flavors, with different pricing and different features, but I chose Memcached because it's free, runs on Linux, is easy to setup, and if MySpace relies on it it must be good enough for my little app. (There's also a Windows implementation that's pretty useful for development and testing.)
But here's the thing. I don't want to write references to the C# Memcached client all over my code. What if I switch to something else? What if the app doesn't need to scale up and needs to rely on ASP.NET cache? Caching, like logging, is one of those aspects that's all over the place and creates dependencies that can be a real pain to refactor.
Here's where a container (like Castle.Windsor) comes in handy. All I had to do was create an ICache interface as follows:
public interface ICache
{
void Set(string key, object value);}
void Set(string key, object value, TimeSpan duration);
object Get(string key);
void Remove(string key);
bool KeyExists(string key);
then I wrote 3 simple implementations:
CacheMocukupImpl uses a private dictionary to organize its contents. It's not thread-safe but is guaranteed to work in any context. Very useful for unit-testing.
ASPNetCacheImpl is a wrapper for the built-in ASP.NET Cache object.
MemCachedImpl uses a MemCached client (there are a couple C# clients out there: here and here).
Then it's just a matter of declaring the ICache component in the Castle configuration, and calling IWindsorContainer.Resolve
Remember to set lifecycle attribute to "singleton", which prevents the class from being instanciated for every single call. Since the cache shares its resources across all incoming requests, it has to be a singleton. Of course, you have to make sure your implementation is thread-safe. Now depending on my needs all I need to do is change the Castle configuration to change my caching implementation. Why not using the ASP.NET provider pattern you might ask? Because I didn't want to limit myself to ASP.NET. I might have other non-web apps that could benefit from this feature. Also, it makes unit testing much easier. Using mockups allows me to focus the test on the method it's testing, and not associated components.
I'm now implementing this pattern all over the place. We're using Amazon Web Services extensively, so I created interfaces, mockups and implementations for queuing and file storage. Logging is next. By decoupling your components, your code becomes much easier to read, test and debug.
0 comments:
Post a Comment