Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,953 | Comments: 44,411

filter by tags archive

Windsor - IHandlerSelector


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: IHandlerSelector.

The interface is defined as:

/// <summary>
/// Implementors of this interface allow to extend the way the container perform
/// component resolution based on some application specific business logic.
/// </summary>
/// <remarks>
/// This is the sibling interface to <seealso cref="ISubDependencyResolver"/>.
/// This is dealing strictly with root components, while the <seealso cref="ISubDependencyResolver"/> is dealing with
/// dependent components.
/// </remarks>
public interface IHandlerSelector
{
    /// <summary>
    /// Whatever the selector has an opinion about resolving a component with the 
    /// specified service and key.
    /// </summary>
    /// <param name="key">The service key - can be null</param>
    /// <param name="service">The service interface that we want to resolve</param>
    bool HasOpinionAbout(string key, Type service);

    /// <summary>
    /// Select the appropriate handler from the list of defined handlers.
    /// The returned handler should be a member from the <paramref name="handlers"/> array.
    /// </summary>
    /// <param name="key">The service key - can be null</param>
    /// <param name="service">The service interface that we want to resolve</param>
    /// <param name="handlers">The defined handlers</param>
    /// <returns>The selected handler, or null</returns>
    IHandler SelectHandler(string key, Type service, IHandler[] handlers);
}

And registering it in the container is simply:

container.Kernel.AddHandlerSelector(selector);

A handler selector is asked if it wants to express an opinion on a particular component resolution, based on key (optional) and type. Assuming we say yes, we are called to select the appropriate handler from all the registered handlers that can satisfy that request.

Let us say that we want to recover from the database being down by serving an implementation that reads from only the cache, we can implement it thusly:

public class DataAccessHandlerSelector : IHandlerSelector
{
	bool databaseIsDown = false;

	public DataAccessHandlerSelector()
	{
		DatabaseMonitor.OnChangedState += 
			state => databaseIsDown = state == DatabaseState.Down;
	}

	public bool HasOpinionAbout(string key, Type service)
	{
		return databaseIsDown && service == typeof(IRepository);
	}

	public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
	{
		return handlers.Where(x=>x.ComponentModel.Implementation == typeof(CacheOnlyRepository)).First();
   	}

}

Now we automatically replace, based on our own logic and the current context what type of component the container should resolve.

I am giving the example of detecting infrastructure change, but as important, and as interesting, is the ability to easily use this in order to select services in a multi tenant environment. We can use this approach to perform service overrides all over the place in a way that is natural, easy and extremely powerful.

Have fun...


Comments

Tim Scott

How did you know I was just wrestling with this issue? I solved it by creating my own selector which returns a concrete instance based on context. It certainly works but has a smell to it.

I am using Binsor. If this is "new" in Windsor, I suppose it is not, as of today, supported by Binsor? I wonder how hard it would be to add it?

Ayende Rahien

It is not in the Rhino Tools repository, but you can just update the reference it and it will work

Tim Scott

What would be the Binsor equivalent for container.Kernel.AddHandlerSelector(selector)?

Ayende Rahien

Something like:

IoC.Kernel.AddHandlerSelector ( )

Complex, isn't it ?

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
  2. Special Offer (2):
    27 May 2015 - 29% discount for all our products
  3. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  4. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  5. Interview question (2):
    30 Mar 2015 - fix the index
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats