Nathan Marlor
Nathan Marlor

Reputation: 176

Ninject convention based bindings + decorators

We're using Ninjects convention based bindings to automatically bind a set of commands and queries to their handlers. So far we have one decorator working using the following.

Bind all without the attribute:

    Kernel.Bind(x =>
      x.FromThisAssembly()
       .SelectAllClasses()
       .InheritedFrom(typeof(ICommandHandler<>))
       .WithoutAttribute<DoCheckAttribute>()
       .BindAllInterfaces());

Bind all with the attribute:

    Kernel.Bind(x =>
      x.FromThisAssembly()
       .SelectAllClasses()
       .InheritedFrom(typeof(ICommandHandler<>))
       .WithAttribute<DoCheckAttribute>()
       .BindAllInterfaces()
       .Configure(c => c.WhenInjectedInto(typeof(DoCheckDecorator<>))));

We tried the following to add another decorator, however this fails.

Bind all without the attribute:

    Kernel.Bind(x =>
      x.FromThisAssembly()
       .SelectAllClasses()
       .InheritedFrom(typeof(ICommandHandler<>))
       .WithoutAttribute<DoCheckAttribute>()
       .WithoutAttribute<DoOtherCheckAttribute>()
       .BindAllInterfaces());

Bind all with the attribute:

    Kernel.Bind(x =>
      x.FromThisAssembly()
       .SelectAllClasses()
       .InheritedFrom(typeof(ICommandHandler<>))
       .WithAttribute<DoCheckAttribute>()
       .WithoutAttribute<DoOtherCheckAttribute>()
       .BindAllInterfaces()
       .Configure(c => c.WhenInjectedInto(typeof(DoCheckDecorator<>))));

    Kernel.Bind(x =>
      x.FromThisAssembly()
       .SelectAllClasses()
       .InheritedFrom(typeof(ICommandHandler<>))
       .WithoutAttribute<DoCheckAttribute>()
       .WithAttribute<DoOtherCheckAttribute>()
       .BindAllInterfaces()
       .Configure(c => c.WhenInjectedInto(typeof(DoOtherCheckDecorator<>))));

Is it possible to achieve this in this way using Ninject? Do we have to roll back to defining each bind manually i.e.?

    Bind<X>.To<Y>.WhenInjectedInto(?)

Ideally we would use syntax such as:

    Bind<X>.To<Y>.WithDecorator<Z>.When(a => a.HasAttribute<DoCheckAttribute>)

Upvotes: 4

Views: 721

Answers (1)

Nathan Marlor
Nathan Marlor

Reputation: 176

So it seems that Ninject already has an extension which can solve this problem. Using the interceptors extension it is possible to write an attribute as:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public sealed class DoCheckAttribute : InterceptAttribute
    {
        public override IInterceptor CreateInterceptor(IProxyRequest request)
        {
            return request.Context.Kernel.Get<DoCheckInterceptor>();
        }
    }

The actual intercept is then written as:

    public class DoCheckInterceptor : IInterceptor
    {
         public void Intercept(IInvocation invocation)
         {
            //Do Work
            invocation.Proceed();
         }
    }

This means the bindings become as simple as:

    Kernel.Bind(x =>
       x.FromThisAssembly()
        .SelectAllClasses()
        .InheritedFrom(typeof(ICommandHandler<>))
        .BindAllInterfaces());

New attributes can now easily be added without any change to the bindings. Multiple attributes can also have the order they run in defined, such as:

     [DoCheck(Order = 0), DoOtherCheck(Order = 1)]
     public class TestClass
     {
     }

Upvotes: 3

Related Questions