Castle Windsor Interceptor to solve caching aspect

1.5k views Asked by At

I recently decided to implement caching using the interceptor functionality from castle. It works fine.

My question: If I wanted to avoid the interceptor for a particular call, what strategy would you suggest using?

I've already determined I could have two implementations of a given service one that supports the caching aspect and one that doesn't. I could then call the appropriate one from wherever. I don't like that for many reasons.

I'd be ok with invalidating the cache at the point I knew it would be invalid, but I couldn't come up with a good solution following this line of thinking that still kept caching concerns out of my code.

2

There are 2 answers

1
Crixo On

I usually use decorators for caching concerns.

About removing / invalidating cache item I came out with a solution event based:
real service exposes events for those behaviors changing the system(for ex adding or update an item), decorator service(caching strategy) registers itseself to those events to manage the cache.

0
Jakob On

I have used caching with the help of castle windsors interceptors and I have had the same problem. Generally a service should not know if a dependency is cache enabled or not. This would be a violation of the single responsibility principle.

If you are NOT ok with this code smell you could:

Register your components as named components with and without caching. Then you could selectively use those named components.

var container = new WindsorContainer();
container.Register(Component.For<CachingInterceptor>()
.Instance(new CachingInterceptor(new Cache(TimeoutStyle.RenewTimoutOnQuery, TimeSpan.FromSeconds(3)))));

container.Register(Component.For<IRepo>().ImplementedBy<Repo>().Named("Without"));
container.Register(Component.For<IRepo>().ImplementedBy<Repo>().Interceptors<CachingInterceptor>().Named("With"));
container.Register(Component.For<Service>());
container.Register(Component.For<Game>().DependsOn(Property.ForKey<IRepo>().Is("With")));

var service = container.Resolve<Service>();
var game = container.Resolve<Game>();

Console.WriteLine("Cache is not used");
service.Invoke();
service.Invoke();

Console.WriteLine();
Console.WriteLine("Cache is used");
game.Invoke();
game.Invoke();

I have this project on github: https://github.com/kobbikobb/Caching

If you are ok with this code smell you could:

1. I have used different interfaces depending on when I want to use caching or not. IService vs IServiceWithCache.

2. Implement a singleton thead safe "caching enabled" service to enable/disable caching. If you want to mock this service you could by implementing it with ambient context.

CacheSettings.Disable();
try
{
    ...
}
finally
{
    CacheSettings.Enable();
}