Search code examples
c#genericsdependency-injectioncastle-windsordecorator

How can I register a generic decorator using Castle Windsor?


I need decorate all based onICommandHandler<T> types using a corresponding DeadlockRetryCommandHandlerDecorator<T> type

I tried this solution, but unfortunately it doesn't work.

container.Register(
    Component.For(typeof(ICommandHandler<>))
    .ImplementedBy(typeof(DeadlockRetryCommandHandlerDecorator<>)));

container.Register(
    AllTypes.FromThisAssembly()
        .BasedOn(typeof(ICommandHandler<>))
        .WithService.Base());

How can i register a generic decorator (DeadlockRetryCommandHandlerDecorator<T>) to wrap all generic ICommandHandler<T> implementations?


Solution

  • currently this is not supported OOTB due to the fact that Windsor always favours mode specific component over an open-generic.

    You can get that working quite easily with an ISubDependencyResolver though. The code below assumes you name the component for your decorator "DeadlockRetryCommandHandlerDecorator"

    public class CommandHandlerResolver : ISubDependencyResolver
    {
        private readonly IKernel kernel;
    
        public FooResolver(IKernel kernel)
        {
            this.kernel = kernel;
        }
    
        public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
        {
            return (dependency.TargetType.IsGenericType &&
                    dependency.TargetType.GetGenericTypeDefinition() == typeof (ICommandHandler<>)) &&
                    (model.Implementation.IsGenericType == false ||
                    model.Implementation.GetGenericTypeDefinition() != typeof (DeadlockRetryCommandHandlerDecorator<>));
        }
    
        public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
        {
            return kernel.Resolve("DeadlockRetryCommandHandlerDecorator", dependency.TargetItemType);
        }
    }
    

    The recommended way of achieving scenarios like that with Windsor however is by using interceptors.