Xerxes Xerxes - 1 year ago 70
C# Question

Generic Decorator pattern using ninject

I am trying to wrap my generic interfaces with a decorator but it simply does not work, it seems to me from the other questions that the only way to do this is by explicitly doing it for each decorator, my question is about whether it is possible to wrap all types that implement a certain interface with a specific Decorater in ninject.

code:

static void BindMediatr(IKernel kernel) {
kernel.Components.Add < IBindingResolver, ContravariantBindingResolver > ();

kernel.Bind(scan => scan.FromAssemblyContaining < IMediator > ()
.SelectAllClasses()
.BindDefaultInterface());

kernel.Bind < SingleInstanceFactory > ().ToMethod(ctx => t => ctx.Kernel.Get(t));
kernel.Bind < MultiInstanceFactory > ().ToMethod(ctx => t => ctx.Kernel.GetAll(t));
kernel.Bind(
x => x.FromThisAssembly()
.SelectAllClasses()
.InheritedFromAny(typeof(IAsyncRequestHandler < , > ))
.BindAllInterfaces());

kernel.Bind(typeof(IAsyncRequestHandler < , > ))
.To(typeof(Decorater < , > ))
.WhenInjectedInto < ApiController > ();
}

public class Decorater < TRequest, TResponse >
: IAsyncRequestHandler < TRequest, TResponse >
where TRequest: IAsyncRequest < TResponse > {
IAsyncRequestHandler < TRequest,
TResponse > _decoratee;

public Decorater(IAsyncRequestHandler < TRequest, TResponse > decoratee) {
_decoratee = decoratee;
}

public Task < TResponse > Handle(TRequest message) {
// do something here
}
}

Answer Source

I found this extension method which does the trick:

public static class KernelExtensions
    {
        /// <summary>
        /// Binds an open generic type to its implementation and adds all its defined decorators
        /// </summary>
        /// <param name="kernel">Ninject Container</param>
        /// <param name="openGenericType">Open generic Type</param>
        /// <param name="assembly">Assembly to scan for the open generic type implementation</param>
        /// <param name="decoratorTypes">Types of the decorators. Order matters. Order is from the most outer decorator to the inner decorator</param>
        public static void BindManyOpenGenericsWithDecorators(this IKernel kernel, Type openGenericType, Assembly assembly, params Type[] decoratorTypes)
        {
            var allImplementations = GetAllTypesImplementingOpenGenericType(openGenericType, assembly);

            foreach (var type in allImplementations.Where(type => !decoratorTypes.Contains(type)))
            {
                var genericInterface = type.GetInterfaces().FirstOrDefault(x => openGenericType.IsAssignableFrom(x.GetGenericTypeDefinition()));

                // real implementation
                var parentType = decoratorTypes.Last();
                kernel.Bind(genericInterface).To(type)
                .WhenInjectedInto(parentType);
            }

            for (var i = 0; i <= decoratorTypes.Count() - 1; i++)
            {
                var decoratorType = decoratorTypes[i];

                if (i == 0)
                {
                    // most outer decorator
                    kernel.Bind(openGenericType).To(decoratorType);
                }
                else
                {
                    // inner decorators
                    var parentType = decoratorTypes[i - 1];
                    kernel.Bind(openGenericType).To(decoratorType)
                        .WhenInjectedInto(parentType);
                }
            }
        }

        private static IEnumerable<Type> GetAllTypesImplementingOpenGenericType(Type openGenericType, Assembly assembly)
        {
            return (from type in assembly.GetTypes()
                    from interfaceType in type.GetInterfaces()
                    let baseType = type.BaseType
                    where
                    (baseType != null && baseType.IsGenericType &&
                    openGenericType.IsAssignableFrom(baseType.GetGenericTypeDefinition())) ||
                    (interfaceType.IsGenericType &&
                    openGenericType.IsAssignableFrom(interfaceType.GetGenericTypeDefinition()))
                    select type);
        }
    }
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download