2

Ninject是否具有可用于修饰类或构造函数以使Ninject忽略它的属性?如何指示Ninject从其隐式绑定列表中隐藏一个类型

我需要摆脱的:

两个 服务构造之间检测到循环依赖。

这是我的代码:

// Abstraction 
public interface ICommandHandler<TCommand> 
{ 
    void Handle(TCommand command); 
} 

// Implementation 
public class ShipOrderCommandHandler 
    : ICommandHandler<ShipOrderCommand> 
{ 
    private readonly IRepository<Order> repository; 

    public ShipOrderCommandHandler(
     IRepository<Order> repository) 
    { 
     this.repository = repository; 
    } 

    public void Handle(ShipOrderCommand command) 
    { 
     // do some useful stuf with the command and repository. 
    } 
} 

我一般装饰:

public TransactionalCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> 
{ 
    private ICommandHandler<TCommand> decoratedHandler; 

    public TransactionalCommandHandlerDecorator(
     ICommandHandler<TCommand> decoratedHandler) 
    { 
     this.decoratedHandler = decoratedHandler; 
    } 

    public void Handle(TCommand command) 
    { 
     using (var scope = new TransactionScope()) 
     { 
      this.decoratedHandler.Handle(command); 
      scope.Complete(); 
     } 
    } 
} 

我的容器注册:

kernel.Bind(typeof(ICommandHandler<>)) 
    .To(typeof(TransactionCommandHandlerDecora‌​tor<>)); 
+1

你可以使用With.Interception作为一种方式来实现相同的效果,但obv装饰器路线是一个非常有效的方法来做到这一点。 – 2012-04-04 19:46:57

+0

我已经阅读了整个Ninject Wiki,并没有找到如何忽略构造函数。有了。是好的解决方案,但不是最优的我需要将它放在每个控制器构造函数中,将Ignore放在导致问题的构造函数上会更合理。 – Tomas 2012-04-05 06:14:11

回答

1

你应该能够使用Contextual BindingBind的带有const的原始接口使他们只能在正确的背景下考虑(即,当他们进入装饰者时)。

我有一个非常相似的这样的When扩展名,如果你仍然在看,那么明天我可以粘贴到这里。

编辑:代码,我脑子里想的(原来它没有做想要直接)

public static class NinjectWhenExtensions 
{ 
    public static void WhenRootRequestIsFor<T>(this IBindingSyntax that) 
    { 
     that.BindingConfiguration.Condition = request => request.RootRequestIsFor<T>(); 
    } 
} 

public static class NinjectRequestExtensions 
{ 
    public static bool RootRequestIsFor<T>(this IRequest request) 
    { 
#if false 
     // Need to use ContextPreservingGet in factories and nested requests for this to work. 
     // http://www.planetgeek.ch/2010/12/08/ninject-extension-contextpreservation-explained/ 
     return RootRequest(request).Service == typeof(T); 
#else 
     // Hack - check the template arg is the interface wer'e looking for rather than doing what the name of the method would actually suggest 
     IRequest rootRequest = RootRequest(request); 
     return rootRequest.Service.IsGenericType && rootRequest.Service.GetGenericArguments().Single() == typeof(T); 
#endif 
    } 

    static IRequest RootRequest(IRequest request) 
    { 
     if (request.ParentRequest == null) 
      return request; 

     return RootRequest(request.ParentRequest); 
    } 
} 

用于连接装饰: -

root.Bind<IEndpointSettings>().To<IAnonymousEndpointSettings>().WhenRootRequestIsFor<IAnonymousService>(); 
root.Bind<IEndpointSettings>().To<IAuthenticatedSettings>().WhenRootRequestIsFor<IServiceA>(); 

编辑2:你应该能够使用创建一个When衍生物,除了当它被Resolved馈送到装饰者时,该衍生物从图片中取得IX的通用绑定。然后,Decorator的Bind可以使用上下文保留(@Remo上有一篇文章)来确保进入上下文,以便您的谓词可以决定,或者您可以将元数据添加到请求中,并让When依赖于。

所以,我想: 1.阅读上下文保存 2.检查/转储进入你的When条件上的要求方面的内容,并确定如何可以适当过滤。

(并希望有人会用一个罐头内衬答案一起去!)

上下文保存扩展可能需要扮演一个角色。

+0

是的,请张贴代码。谢谢! – Tomas 2012-04-05 05:50:50

+0

@Tomas更新。稍后再来。 – 2012-04-05 07:51:08

+0

@Tomas再次更新。对不起,它没有完整的工作代码与测试 - 没有得到时间来做它,有趣和所有这一切都是为了解决它! – 2012-04-05 09:01:51

2

这是一个基于您的代码的工作示例。

public class AutoDecorationFacts 
{ 
    readonly StandardKernel _kernel = new StandardKernel(); 

    public AutoDecorationFacts() 
    { 
     _kernel.Bind(typeof(ICommandHandler<>)) 
      .To(typeof(TransactionalCommandHandlerDecorator<>)) 
      .Named("decorated"); 
    } 

    [Fact] 
    public void RawBind() 
    { 
     _kernel.Bind(typeof(ICommandHandler<>)).To<ShipOrderCommandHandler>().WhenAnyAnchestorNamed("decorated"); 
     VerifyBoundRight(); 
    } 

    void VerifyBoundRight() 
    { 
     var cmd = _kernel.Get<ICommandHandler<ShipOrderCommand>>(); 
     Assert.IsType<TransactionalCommandHandlerDecorator<ShipOrderCommand>>(cmd); 
    } 

最佳效果Ninject.Extensions.Conventions使用: -

[Fact] 
    public void NameSpaceBasedConvention() 
    { 
     _kernel.Bind(scan => scan 
      .FromThisAssembly() 
      .SelectAllClasses() 
      .InNamespaceOf<CommandHandlers.ShipOrderCommandHandler>() 
      .BindAllInterfaces() 
      .Configure(x => x.WhenAnyAnchestorNamed("decorated"))); 
     VerifyBoundRight(); 
    } 

    [Fact] 
    public void UnconstrainedWorksTooButDontDoThat() 
    { 
     _kernel.Bind(scan => scan 
      .FromThisAssembly() 
      .SelectAllClasses() 
      .BindAllInterfaces() 
      .Configure(x=>x.WhenAnyAnchestorNamed("decorated"))); 
     VerifyBoundRight(); 
    } 
} 

你的类:

公共类ShipOrderCommand { }

// Abstraction 
public interface ICommandHandler<TCommand> 
{ 
    void Handle(TCommand command); 
} 

// Implementation 
namespace CommandHandlers 
{ 
    public class ShipOrderCommandHandler 
     : ICommandHandler<ShipOrderCommand> 
    { 
     public ShipOrderCommandHandler(
      ) 
     { 
     } 

     public void Handle(ShipOrderCommand command) 
     { 
      // do some useful stuf with the command and repository. 
     } 
    } 
} 
public class TransactionalCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> 
{ 
    private ICommandHandler<TCommand> decoratedHandler; 

    public TransactionalCommandHandlerDecorator(
     ICommandHandler<TCommand> decoratedHandler) 
    { 
     this.decoratedHandler = decoratedHandler; 
    } 

    public void Handle(TCommand command) 
    { 
     this.decoratedHandler.Handle(command); 
    } 
} 

(使用的NuGet - 最新Ninject的版本和Ninject.Extensions.Conventions)

+0

如何在事务装饰器(即ExecutionTimeCommandHandlerDecorator)上添加另一个装饰器? – 2013-07-11 03:27:25

+0

@Discofunk查看https://github.com/ninject/ninject/wiki/Contextual-Binding通常,使用'WhenInjectedInto'和朋友(上面的'.Named'技巧是因为您指出不是作曲和诚实看着它,我不知道是谁写的!) – 2013-07-11 10:10:55