Reputation: 176
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
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