Ninject: Как настроить привязки на основе цепочки зависимостей - PullRequest
2 голосов
/ 19 июля 2009

Хорошо, зависимость от ниндзя, вот вам ...

Я хочу изменить способ, которым Ninject создает зависимость на основе типа, который я запрашиваю из Ядра.

У меня есть класс DbConnectionFactory со следующими конструкторами:

    public DbConnectionFactory()
        : this(MyDatabase.ConnectionString)
    {
    }

    public DbConnectionFactory(string connectionString)
        : this(DbProviderFactories.GetFactory("System.Data.SqlClient"), connectionString)
    {
    }

Для привязки по умолчанию я хочу, чтобы Ninject использовал конструктор без параметров:

        this.Bind<IDbConnectionFactory>().To<DbConnectionFactory>();

Некоторым классам в моем коде нужен Ninject для предоставления параметра connectionString. Я попытался настроить привязку так:

        this.Bind<IDbConnectionFactory>().To<DbConnectionFactory>().Only(
            When.Context.InstanceOf(typeof(IRepository))).WithArgument(
            "connectionString", MyOtherDatabase.ConnectionString);

Однако я только когда-либо заставлял Ninject использовать конструктор по умолчанию.

Я, должно быть, упускаю что-то очевидное!

Ответы [ 2 ]

3 голосов
/ 21 июля 2009

Звучит так, как будто здесь слишком много слоев. Зачем вам нужен DatabaseGateway? Почему вы не используете фабрики провайдеров ADO.NET для создания соединений (вы также можете подключать их через Ninject) для непосредственного управления своими соединениями? ИЛИ еще лучше, с шаблоном хранилища использовать что-то вроде NHibernate и использовать это для сопоставления объектов?

В любом случае, как насчет того, чтобы всегда использовать более длинный конструктор и попеременно передавать либо MyDatabase.ConnectionString, либо MyOtherDatabase.ConnectionString в зависимости от ситуации? Вы можете использовать провайдера, как описано здесь и здесь , но я стараюсь избегать их, если в этом нет крайней необходимости:

  1. Определить два новых атрибута

    public class DefaultDatabaseAttribute : Attribute {}
    public class OtherDatabaseAttribute : Attribute {}
    
  2. Украсить аргументы DatabaseGateway соответствующими атрибутами в конструкторе

    public class OneRepository : IRepository
    {
        public OneRepository([DefaultDatabase]DatabaseGateway factory)
        {
        }
    }
    
    public class TwoRepository : IRepository
    {
        public TwoRepository([OtherDatabase]DatabaseGateway factory)
        {
        }
    }
    

    и ваш провайдер будет выглядеть так:

    public class DatabaseGatewayProvider : SimpleProvider<DatabaseGateway>
    {
            protected override DatabaseGateway CreateInstance(Ninject.Core.Activation.IContext context)
            {
                IDbConnectionFactory factory;
                if (context.Member.IsDefined(typeof(DefaultDatabaseAttribute), false))
                {
                    factory = context.Kernel.get<IDbConnectionFactory>(With.Parameters.ConstructorArgument("connectionString", MyDatabase.ConnectionString)));
                }
                else if (context.Member.IsDefined(typeof(OtherDatabaseAttribute), false))
                {
                    factory = context.Kernel.get<IDbConnectionFactory>(With.Parameters.ConstructorArgument("connectionString", MyOtherDatabase.ConnectionString)));
                }
    
                return new DatabaseGateway(factory);
            }
    }
    

Вы можете расширить эту модель, добавив дополнительные атрибуты, чтобы решить, нужно ли возвращать фабрику в DatabaseGateway.

Это неудобно, но может быть лучшим, что вы можете сделать, учитывая количество слоев.

1 голос
/ 14 сентября 2009

Эта статья также может вам помочь. Как сказал Джефф, вы захотите использовать With.Parameters.ConstructorArgument (). Вы можете передать несколько аргументов, продолжая цепочку ConstructorArgument или используя словарь. Надеюсь, это поможет!

...