Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order when calling ResolveAll in Castle Windsor

Assume that I have multiple objects registered in the container, all implementing the same interface:

container.Register(
    Component.For<ITask>().ImplementedBy<Task1>(),
    Component.For<ITask>().ImplementedBy<Task2>(),
    Component.For<ITask>().ImplementedBy<Task3>(),
    Component.For<ITask>().ImplementedBy<Task4>(),
);

And I wish to resolve all the implementations of ITask:

var tasks = container.ResolveAll<ITask>();

Is there a way to control the order of the resolved instances?

Note: Obviously, I can implement an Order or Priority property on ITask, and just sort the list of tasks, but I am looking for a lower-level solution.

like image 343
SaguiItay Avatar asked Oct 27 '14 08:10

SaguiItay


2 Answers

I believe that what you are looking for is a Handler Filter which based on the scarce documentation and the breaking changes in Windsor Castle 3; it provides filtering and sorting of components. Here's an extract from their Wiki page

The interface is similar to IHandlerSelector but allow you to filter/sort handlers requested by container.ResolveAll() method

So basically you will need to implement the IHandlerFilter interface and then add this implementation to the kernel while initializing the Windsor container. From the source code, this interface looks something similar to this...

public interface IHandlerFilter
{
    bool HasOpinionAbout(Type service);
    IHandler[] SelectHandlers(Type service, IHandler[] handlers);
}

Adding the Handler Filter to the kernel would be something like below...

 var container = new WindsorContainer()
        .Install(Configuration.FromXmlFile("components.config"));
        container.Kernel.AddHandlersFilter(new YourHandlerFilterImplementation());

and then when resolving all components of a services with ResolveAll the order will be sorted (and filtered) based on your own implementation

like image 174
Leo Avatar answered Nov 04 '22 10:11

Leo


I second Leo's advice that what you're after is a handlers filter.

On my blog I have this example on how a simple handlers filter can be made, which happens to be one that results in ordered task instances when they're resolved through ResolveAll<ITask> (or when an IEnumerable<ITask> gets injected):

class TaskHandlersFilter : IHandlersFilter
{
    readonly Dictionary<Type, int> sortOrder = 
        new Dictionary<Type, int>
        {
            {typeof (PrepareSomething), 1},
            {typeof (CarryItOut), 2},
            {typeof (FinishTheJob), 3},
        };

    public bool HasOpinionAbout(Type service)
    {
        return service == typeof(ITask);
    }

    public IHandler[] SelectHandlers(Type service, IHandler[] handlers)
    {
        // come up with some way of ordering implementations here
        // (cool solution coming up in the next post... ;))
        return handlers
            .OrderBy(h => sortOrder[h.ComponentModel.Implementation])
            .ToArray();
    }
}

I also have a more elaborate example that plays around with the API used to specify the ordering - in this case, I'm allowing for the types to specify their position relative to another type, e.g. like

[ExecutesBefore(typeof(ExecutePayment))]
public class ValidateCreditCards : ITask { ... }

which might/might not be useful in your concrete situation :)

like image 4
mookid8000 Avatar answered Nov 04 '22 08:11

mookid8000