【问题标题】:How to instruct Ninject hide a Type from its implicit binding list如何指示 Ninject 从其隐式绑定列表中隐藏类型
【发布时间】:2012-04-04 14:30:54
【问题描述】:

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

【问题讨论】:

  • 您可以使用 With.Interception 作为实现相同效果的一种方式,但装饰器路由是一种非常有效的方式。
  • 我已经阅读了整个 Ninject Wiki,但没有找到如何忽略构造函数。和。是一个很好的解决方案,但不是最优的我需要将它放在每个控制器构造函数中,将 Ignore 放在导致问题的构造函数上会更合理。

标签: .net dependency-injection ninject ioc-container ninject.web.mvc


【解决方案1】:

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

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)

【讨论】:

  • 如何在事务装饰器之上添加另一个装饰器(即 ExecutionTimeCommandHandlerDecorator)?
  • @Discofunk 见github.com/ninject/ninject/wiki/Contextual-Binding 通常,一个人使用WhenInjectedInto 和朋友(上面的.Named 技巧正如你指出的那样不是组合式的,老实说看看它,我想知道是谁写的它!)
【解决方案2】:

您应该能够使用带有约束的 Contextual BindingBind 原始接口,以使它们仅在正确的上下文中被考虑(即,当它们进入装饰器时)。

我有一个非常相似的 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 衍生物,它将 IX 的一般绑定排除在图片之外,除非将 Resolved 输入到装饰器中。然后,您的装饰器的Bind 可以使用上下文保留(@Remo 有一篇文章)来确保进入上下文以便您的谓词可以决定,或者您可以将元数据添加到请求并拥有何时依赖关于那个。

所以,我会: 1. 阅读上下文保留 2. 检查/转储进入When 条件的请求的上下文内容,并确定如何适当过滤。

(希望有人能提供一个罐头的单线答案!)

上下文保留扩展可能会发挥作用。

【讨论】:

  • @Tomas 再次更新。抱歉,它不是带有测试的完整工作代码 - 目前没有时间去做,很有趣,而且一切都可以解决!
猜你喜欢
  • 2017-03-19
  • 1970-01-01
  • 2012-08-14
  • 1970-01-01
  • 2020-11-19
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 2012-08-25
相关资源
最近更新 更多