views:

338

answers:

2

I have a group of classes that implement an interface for my application start-up activities. Here is the registration code:

private static void ConfigureContainer()
{
    var container = new WindsorContainer();

    container.Register(AllTypes.Of<IStartupTask>()
             .FromAssembly(Assembly.GetExecutingAssembly()))
    ...

    var serviceLocator = container.Resolve<IServiceLocator>();
    ServiceLocator.SetLocatorProvider(() => serviceLocator);
}

In order to get the tasks, I use this and it works as expected:

public static void Run()
{
    var tasks = ServiceLocator.Current.GetAllInstances<IStartupTask>();

    foreach (var task in tasks)
    {
       task.Execute();
    }
}

Here is my problem: I have one task that depends on another being run first. There is an InitializeDatabase task that needs to run before the PopulateDatabse task. There are also a bunch of other tasks that are run and I would rather not split the InitializeDatabase task out, if there is some Castle config that will allow me to order the resolution of the types. I don't want to specify the complete order of the types being resolved since that defeats the purpose of the automatic registration, just that InitializeDatabase is the first or PopulateDatabase is last.

Is there a way to register which types should be resolved first without specifying the order of all the types?

+1  A: 

Here's one way to do it, it might not be very pretty but it works:

[AttributeUsage(AttributeTargets.Class)]
public class FirstAttribute: Attribute {}
public interface IService {}
public class ThirdService : IService { }
[First]
public class FirstService : IService { }
public class SecondService: IService {}

[Test]
public void WindsorOrder() {
    var container = new WindsorContainer();

    container.Register(AllTypes.Of<IService>()
        .FromAssembly(Assembly.GetExecutingAssembly()));

    var intf = container.ResolveAll<IService>()
        .OrderByDescending(i => i.GetType().GetCustomAttributes(typeof(FirstAttribute), true).Length)
        .ToArray();
    Assert.IsInstanceOfType(typeof(FirstService), intf[0]);
}

If you remove [First] from FirstService, the first will be ThirdService and the test will fail.

Mauricio Scheffer
A: 

Use HandlerSelector for that

Krzysztof Koźmic
Thanks for the pointer. I looked at HandlerSelector but I didn't see how I could use it for this case. HandlerSelector.SelectHandler() is called for every implementation of IStartupTask, so I'm not sure how to order the service resolutions from there. Am I using HandleSelector wrong?
Steven Lyons