How can I register a generic decorator using Castl

2019-01-09 11:59发布

问题:

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?

回答1:

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.



回答2:

I had the same issue. I managed to resolve it by registering each type explicity as more specific type. For me this solution is more clear than using sub dependency resolver

var commandTypes = businessAssembly.GetTypes()
    .Where(t => !t.IsInterface && typeof(ICommand).IsAssignableFrom(t));

foreach(var commandType in commandTypes)
{
    var handlerInterface = typeof(ICommandHandler<>).MakeGenericType(new[] { commandType });
    var transactionalHandler = typeof(DeadlockRetryCommandHandlerDecorator<>).MakeGenericType(new[] { commandType });
    container.Register(Component.For(handlerInterface)
        .ImplementedBy(transactionalHandler)
        .LifeStyle.PerWebRequest);
}