Подтвердить что ты не робот

Как зарегистрировать несколько экземпляров IDbConnectionFactory с помощью Funq в ServiceStack.net

Как вы собираетесь регистрировать разные экземпляры IDbConnectionFactory в Funq, а затем обращаться к ним непосредственно в своих сервисах? Именованные экземпляры каким-то образом вступают в игру здесь?

Это лучший подход, который можно использовать при использовании разных баз данных через службы?

Спасибо!

EDIT:

Пример;). Я мог бы быть здесь, потому что я довольно новичок в IoC, но скажу, например, что у меня есть два отдельных соединения с базой данных, которые я бы хотел ввести. В ServiceStack это делается в Global.asax.

container.Register<IDbConnectionFactory>(c =>
            new OrmLiteConnectionFactory(@"Connection String 1", SqlServerOrmLiteDialectProvider.Instance));                                             

container.Register<IDbConnectionFactory>(c =>
            new OrmLiteConnectionFactory(@"Connection String 2", SqlServerOrmLiteDialectProvider.Instance));                

Оба эти, кажется, инъецируются хоккой дори.

Затем они автоматически запускаются в конце службы через что-то вроде этого:

public IDbConnectionFactory DbFactory { get; set; }

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

Здесь приведен полный пример из ServiceStack.Examples, который использует только 1 IDbConnectionFactory: Показ фильмов

4b9b3361

Ответ 1

Мой вопрос выше по-прежнему действителен, но в любом случае вам может помочь следующее.

Funq не поддерживает автоматическую вставку конструктора (автоматическая проводка a.k.a.), и вам придется сделать это вручную, построив выражения Func<T> лямбда. Поскольку вы уже делаете инъекцию конструктора вручную, легко выбрать, что IDbConnectionFactory вы хотите ввести в свои службы. Пример:

IDbConnectionFactory yellowDbConFactory =
    new YellowDbConnectionFactory();

IDbConnectionFactory blueDbConFactory =
    new BlueDbConnectionFactory();

IDbConnectionFactory purpleDbConFactory =
    new PurpleDbConnectionFactory();

container.Register<IService1>(c =>
    new Service1Impl(yellowDbConFactory,
        c.Resolve<IDep1>());

container.Register<IService2>(c =>
    new Service2Impl(blueDbConFactory);

container.Register<IService3>(c =>
    new Service3Impl(purpleDbConFactory, 
        c.Resolve<IDep2>());

Конечно, вы также можете использовать именованные регистрации, например:

container.Register<IDbConnectionFactory>("yellow",
    new YellowDbConnectionFactory());

container.Register<IDbConnectionFactory>("blue",
    new BlueDbConnectionFactory());

container.Register<IDbConnectionFactory>("purple",
    new PurpleDbConnectionFactory());

container.Register<IService1>(c =>
    new Service1Impl(
        c.Resolve<IDbConnectionFactory>("yellow"),
        c.Resolve<IDep1>());

container.Register<IService2>(c =>
    new Service2Impl(
        c.Resolve<IDbConnectionFactory>("blue"));

container.Register<IService3>(c =>
    new Service3Impl(
        c.Resolve<IDbConnectionFactory>("purple"), 
        c.Resolve<IDep2>());

Из-за отсутствия поддержки для автоматической проводки вы закончите с этими довольно неудобными регистрациями, и это довольно скоро приведет к кошмару обслуживания вашего корня композиции, но не связанному с вашим вопросом; -)

Обычно вы должны стараться предотвратить неоднозначность при регистрации. В вашем случае у вас есть один интерфейс, который выполняет две функции (подключается к двум базам данных). Если обе базы данных не разделяют одну и ту же модель, каждая база данных заслуживает собственного интерфейса (если две реализации не взаимозаменяемы, вы будете нарушать Принцип замены Лискова):

interface IYellowDbConnectionFactory : IDbConnectionFactory
{
}

interface IPurpleDbConnectionFactory : IDbConnectionFactory
{
}

Из-за того, как работает ServiceStack, вам, вероятно, необходимо реализовать реализацию для каждого:

class YellowDbConnectionFactory : OrmLiteConnectionFactory,
    IYellowDbConnectionFactory
{
    public YellowDbConnectionFactory(string s) : base(s){}
}

class PurpleDbConnectionFactory : OrmLiteConnectionFactory,
    IPurpleDbConnectionFactory 
{
    public YellowDbConnectionFactory(string s) : base(s){}
}

Теперь вы должны изменить определение своих сервисов для использования конкретного интерфейса вместо использования IDbConnectionFactory:

public class MovieService : RestServiceBase<Movie>
{
    private readonly IYellowDbConnectionFactory dbFactory;

    public MovieService(IYellowDbConnectionFactory factory)
    {
        this.dbFactory = factory;
    }
}

Обратите внимание, что этот класс теперь использует инъекцию конструктора вместо инъекции свойства. Вы можете заставить это работать с инъекцией свойств, но обычно лучше идти с инжектором конструктора. Вот SO вопрос об этом.

С помощью Funq ваша конфигурация будет выглядеть следующим образом:

container.Register<MovieService>(c =>
    new MovieService(
        c.Resolve<IYellowDbConnectionFactory>());

Эти два новых интерфейса и два класса и переход на MovieService не выиграли вас много, потому что Funq не поддерживает автоматическую проводку. Вы будете тем, кто проводит все вместе вручную. Однако, когда вы переключаетесь на фреймворк, который поддерживает автоматическую проводку, этот проект позволяет контейнеру вводить правильные зависимости без проблем, потому что нет обсуждения того, что нужно вводить.

Ответ 2

Хотя Funq не поддерживает автоматическую проводку, ServiceStack ее реализация. Последняя версия ServiceStack включает перегрузку Funq.Container:

container.RegisterAutoWired<T>();
container.RegisterAutoWiredAs<T,TAs>();
container.RegisterAs<T,TAs>();

Итак, в примере Стивена вы также можете:

container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>();

И он автоматически зарегистрирует для вас зависимости.

Ответ 3

Думал, что чип в моих 2 центах здесь, хотя я понимаю, что вопрос довольно старый. Я хотел получить доступ к транзакционной БД и БД регистрации из ServiceStack, и именно так я закончил это с помощью метода AppHostBase Configure():

            container.Register<IDbConnectionFactory>(
                c => {
                    OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory(ConfigurationManager.ConnectionStrings["MyTransactionalDB"].ConnectionString, MySqlDialect.Provider);
                    dbFactory.ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current);
                    dbFactory.RegisterConnection("LoggingDB", ConfigurationManager.ConnectionStrings["MyLoggingDB"].ConnectionString, MySqlDialect.Provider);

                    return dbFactory;
                });

По умолчанию "MyTransactionalDB" используется при открытии соединения из factory, но я могу явно обращаться к БД регистрации из службы через:

        using (var db = DbFactory.Open("LoggingDB"))
        {
            db.Save(...);
        }

Ответ 4

Попробуйте использовать шаблон репозитория вместо этого IoC (что просто усложняет вещи без необходимости). Вышеприведенный код, похоже, не работает. Подозреваю, что что-то изменилось. Я все еще не понимаю, как регистрировать IDbConnectionFactory магически заполняет свойство IDbConnection. Понадобилось бы некоторое объяснение вокруг этого. Если кто-то когда-либо будет работать с использованием контейнера ServiceStack IoC, тогда мне будет интересно посмотреть, как это сделать. И было бы очень полезно обновить документы SS (я очень рад это сделать)