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

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

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

Спасибо!

EDIT:

Пример;). Я мог бы быть далеко отсюда, потому что я довольно плохо знаком с IoC, но скажем, например, у меня есть 2 отдельных соединения с базой данных, которые я хотел бы внедрить. В 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: Фильмы Отдых

Ответы [ 4 ]

14 голосов
/ 07 января 2012

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

Funq не поддерживает автоматическое внедрение конструктора (так называемое автоматическое подключение), и вам придется делать это вручную, создавая 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 не поддерживает автоматическое подключение.Вы будете тем, кто соединяет все вместе вручную.Однако, когда вы переключаетесь на платформу, которая поддерживает поддержку автоматического подключения, эта конструкция позволяет контейнеру без проблем вводить нужные зависимости, потому что нет обсуждения того, что вводить.

11 голосов
/ 08 января 2012

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

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

Так что в примере Стивена вы также можете сделать:

container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>();

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

3 голосов
/ 25 октября 2015

Я подумал, что смогу поставить свои 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соединение с завода, но я могу явно получить доступ к базе данных журналов из службы через:

        using (var db = DbFactory.Open("LoggingDB"))
        {
            db.Save(...);
        }
1 голос
/ 13 октября 2013

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

...