2

Ninject には、Ninject に無視させるためにクラスまたはコンストラクターを装飾するために使用できる属性がありますか?

私は取り除く必要があります:

2 つのサービスのコンストラクター間で循環依存関係が検出されました。

これは私のコードです:

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

2 に答える 2

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の最新バージョン)

于 2012-04-05T14:12:48.873 に答える
1

制約付きのrawインターフェイスへのContextualBindingを使用して、適切なコンテキストでのみ考慮されるようにすることができるはずですBind(つまり、デコレータに入るとき)。

私は非常によく似たそのような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の一般的なバインディングを画像から取り除く派生物の作成を使用できるはずです。Resolve次に、Bindデコレータのforは、コンテキスト保存(@Remoに記事があります)を使用して、述語が決定できるようにコンテキストに入るようにするか、メタデータをリクエストに追加して、Whenをそれに依存させることができます。

したがって、次のようにします。1.コンテキストの保存について読みます。2。When条件に入ったリクエストのコンテキストの内容を調べてダンプし、適切にフィルタリングする方法を決定します。

(そして、誰かが缶詰のワンライナーの答えを持って来ることを願っています!)

Context Preservation拡張機能は、役割を果たす可能性があります。

于 2012-04-04T19:50:39.993 に答える