Question

We use the CollectionResolver in Castle.Windsor (3.1) for injecting a set of components. The order of those is relevant. Currently we use a Position property on the service for ordering them.

As we use the same master component in different applications with a different set of components, the position property is a maintenance burden. It implies knowledge of the components on each other. Also the single component should not know about others.

We want something like registering multiple IComparer<Type> for specific service type to control the order of the injected components.

Is there a simple (predefined) way to do this in Castle.Windsor or has anybody done something like this before?

Example of what we want to replace:

interface IService
{
   bool Do();
   int Position { get; } // <= This should be kicked!
}

class Master
{
   private readonly IService[] _services;

   public Master(IService[] services)
   {
       // Master should not care about ordering also,
       // but injecting a sorter would be acceptable
       _services = services.OrderBy(s => s.Position).ToArray();
   }

   public void Do()
   {
       foreach(var service in _services)
       {
          if(!service.Do())
             break;
       }
    }
}

We want something like the above without Position using a component like this:

class OrderService : IComparer<Type>
{       
   public int Compare(Type x, Type y)
   {
      if(typeof(MoreImportantComponent) == x)
         return -1;
      else
         return 0;

   }
}
Was it helpful?

Solution

You can affect the order of services using an IHandlersFilter implementation

public class ServiceHandlersFilter : IHandlersFilter
{
    private readonly List<Type> sortOrder = new List<Type>
                                                {
                                                   { typeof(Service1) },
                                                   { typeof(Service2) },
                                                   { typeof(Service3) },
                                                };

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

    public IHandler[] SelectHandlers(Type service, IHandler[] handlers)
    {
        return handlers
            .OrderBy(h => sortOrder.IndexOf(h.ComponentModel.Implementation))
            .ToArray();
    }
}

You may want the sort order to be determined more elegantly, for example, by the components themselves. If that is the case, check out this RespectOrderDirectivesHandlersFilter implementation. As per mookid's blog post on the filter, you can attribute your IService implementations with the ExecutesBeforeAttribute and ExecutesAfterAttribute attributes to imply order of execution relative to each other.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top