Windsor - IModelInterceptersSelector
In my previous post I introduced the basis of context as an architectural pattern. Now I want to talk about how we can implement that using Windsor and a new extensibility point: IModelInterceptersSelector.
The interface is defined as:
/// <summary> /// Select the appropriate interecptors based on the application specific /// business logic /// </summary> public interface IModelInterceptorsSelector { /// <summary> /// Select the appropriate intereceptor references. /// The intereceptor references aren't neccessarily registered in the model.Intereceptors /// </summary> /// <param name="model">The model to select the interceptors for</param> /// <returns>The intereceptors for this model (in the current context) or a null reference</returns> /// <remarks> /// If the selector is not interested in modifying the interceptors for this model, it /// should return a null reference and the next selector in line would be executed (or the default /// model.Interceptors). /// If the selector return a non null value, this is the value that is used, and the model.Interectors are ignored, if this /// is not the desirable behavior, you need to merge your interceptors with the ones in model.Interecptors yourself. /// </remarks> InterceptorReference[] SelectInterceptors(ComponentModel model); /// <summary> /// Determain whatever the specified has interecptors. /// The selector should only return true from this method if it has determained that is /// a model that it would likely add interceptors to. /// </summary> /// <param name="model">The model</param> /// <returns>Whatever this selector is likely to add intereceptors to the specified model</returns> bool HasInterceptors(ComponentModel model); }
And registering it in the container is simply:
container.Kernel.ProxyFactory.AddInterceptorSelector(selector);
Interceptors are the basis of AOP, but traditionally, you didn't get a lot of choices in how you compose your interceptors at runtime. Using IModelInterceptersSelector make it extremely easy to modify the selection of interceptors based on relevant business logic.
Let us take the following example. We have a warehouse service that we want to add caching to. However, we can't use the cache in the request comes from the fulfillment service. First, we define the caching interceptor, then, we define the logic that controls adding or removing it.
public class WarehouseCachingInterceptorSelector : IModelInterceptorsSelector { public InterceptorReference[] SelectInterceptors(ComponentModel model) { if(model.Service!=typeof(IWarehouse)) return null; if(Origin.IsFromFulfillment) return null; return new InterceptorReference[]{new InterceptorReference(typeof(WarehouseCachingInterceptor)), }; } public bool HasInterceptors(ComponentModel model) { return model.Service == typeof (IWarehouse); } }
And now we get caching for everything except for fulfillment. And we get this in a clean and very easy to understand way. :-D
Comments
Oren You are an alien !! No human being can post so fast ! ;)
PS: You are doing geat job. thanks !
I can tell by the font and font anti-aliasing that you're writing this code on a Mac, what's your set-up like?
I run VS.NET through Parallels and it's pretty slow and the font anti-aliasing isn't as nice.
Jim,
That particular post was written on a fusion VM windows machine. No idea how you figured out that I am running on the mac
As for developing on the mac, I am using fusion most of the time, and it just works.
I like this implementation. Clean and concise.
While we're on it, what would be the best way of doing similar thing upon creation.
Lets say we have a warehouse and customers. Each customer has ICustomerAdvisor (as a property) that will advise differently based on customers address (different countries, different taxes, and border crossing policies). Never mind the model.
What would be the best place to put the logic that would determine which advisor to put into each customer? Since address does not usually change during object' lifetime it would be reasonable to do it sometime during creation (but we already need an address for the customer, to be able to use it to select best advisor).
Krzysztof,
IHandlerSelector is the one
Reading comprehention. I'll better go to sleep, instead of asking stupid questions ;)
Ok, maybe that was not so stupid question after all (or I really need to go to sleep).
If I use IHandlerSelector I'm only provided with type, key and candidates for handles for service that was asked of me. I don't have, however any information about the object (the customer in my example) the service (ICustomer Advisor) is asked for. So I still don't know the address, (unless I come up with a convention, like having address tuneled into the key).
Am I missing something important here?
I imagined it, as something behaving more like a classic factory, wher e I don't have to register implementations of ICustomerAdvisor. Instead I register the 'factory' and it, based on contextual information (the address in this case) returns configured implementations.
I suspect a facility might do it, but it feels like using a shotgun to kill a fly.
I might also have customers having IAdvisorFactory, that looks like this:
public interface IAdvisorFactory
{
ICustomerAdvisor CreateAdvisor(AbstractCustomer customer);
}
and then call factory.CreateAdvisor(this), but its polluting domain model with infrastructure, and it smells.
So, what's my best option?
Oh, if that is what you want, you would need to use ISubDependencyResolver, which gives you a lot more knowledge about the current resolution
Note however that if you are creating this customer from the container, it wouldn't need to first resolve its dependencies, and then create it. So you wouldn't have the customer instance until you have the advisors instances
Probably you should look at http://www.qi4j.org/ - java framework for Composite Oriented Programming. They use context as a central part of the design
Comment preview