Do you know what handler selectors are? It’s a way for you to register some logic in Windsor that will choose among all the available handlers when some particular component is resolved.
E.g. if you have a multi-tenant application with multiple implementations of IUserNotifier, let’s call them NotifyUserBySms and NotifyUserByEmail, and you need to make sure that one particular tenant whose employees are equipped with smartphones get notified by email, you can let a handler selector make this selection transparent to the rest of your application by adding a handler selector, like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class UserNotificationHandlerSelector : IHandlerSelector { public bool HasOpinionAbout(string key, Type service) { return service == typeof (IUserNotifier); } public IHandler SelectHandler(string key, Type service, IHandler[] handlers) { // somehow determine whether employees of current tenant can receive emails Console.WriteLine("Does the current tenant' s employees have smartphones? (y/n)"); switch (char.ToLower(Console.ReadKey().KeyChar)) { case 'y': return handlers.Single(h => h.ComponentModel.Implementation == typeof (NotifyUserByEmail)); default: return handlers.First(h => h.ComponentModel.Implementation != typeof (NotifyUserByEmail)); } } } |
thus making it possible for all other services to depend on IUserNotifier, not caring under which tenant’s context they’re running.
As you can see, this handler selector only has an opinion when an IUserNotifier is being resolved. And then, when its SelectHandler method is invoked, it gets to choose among all assignable handlers for that particular service type, effectively providing a way to make sure that some particular implementation is used, given some condition (here simulated by some Console.ReadKey() action).
Nifty huh? Only sad thing though, is that handler selectors are not pulled from the container – you have to supply an instance to the kernel, so if you need some services in the selector you need to pull them manually from the container. This can of course be overcome by supplying the handler selector with a reference to the container, allowing it to Resolve stuff at will – just remember – as always – to Release what you Resolve.
This was a short introduction to handler selectors – next post will be about something new, namely handler filters which is a new feature in Windsor 3.0.