使用 ninject 的通用装饰器模式

Generic Decorator pattern using ninject

我试图用装饰器包装我的通用接口,但它根本不起作用,在我看来,从其他问题来看,唯一的方法是为每个装饰器显式地这样做,我的问题是关于是否可以用 ninject.

中的特定装饰器包装所有实现特定接口的类型

代码:

 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
   }
  }

如果您需要修饰所有实现接口的类中的某个方法的调用,您可以尝试代理所有绑定。

Ninject 有一个名为 - Interception 的扩展,它允许您拦截对您方法的特定调用并通过某种逻辑将其包装。

Here 是一篇关于此的好文章。

希望对你有帮助。

我发现这个扩展方法可以解决问题:

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);
        }
    }