2012-01-06 41 views
18

如何在Funq中注册不同的IDbConnectionFactory实例,然后直接在您的服务中访问它们?不知怎的,命名实例在这里发挥作用了吗?如何在ServiceStack.net中使用Funq注册多个IDbConnectionFactory实例

这是跨服务使用不同数据库时采取的最佳方法吗?

谢谢!

编辑:

一个例子)。我可以在这里休息,因为我对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; } 

在这种情况下,这似乎是给我的第一个注册。我如何才能访问服务端的特定服务?希望这可以让它更清楚一点。

下面是仅使用1个IDbConnectionFactory ServiceStack.Examples一个羽翼丰满的例子: Movies Rest

+0

你能显示一些代码吗?我想我们可以给你一些关于你的应用程序设计的提示,但为此,我们需要更多的实际设计见解。看看在哪些服务中注入了这些IDbConnectionFactory实例,以及这些服务如何处理这些IDbConnectionFactory依赖关系会很有趣。 – Steven 2012-01-07 00:23:25

+0

但请注意,Funq是一个非常简单的IoC容器(有些甚至可能认为它不是IoC容器),而且所有东西都必须通过手工连接。但是,您可以在创建的每项服务中注入所需的一切。 – Steven 2012-01-07 00:25:55

+0

我更新了这个问题,使其更加清晰,并在Simple Injector上找到了您的文章。我希望通过现在的阅读来加深对IoC的理解。 – 2012-01-07 03:24:33

回答

14

上面我的问题仍然有效,但以下可能会帮助你的好意。

Funq不支持自动构造函数注入(a.k.a.自动布线),您将不得不通过构造Func<T> lambda表达式来手动执行此操作。因为您已经手动进行构造函数注入,所以很容易选择您希望注入到服务中的什么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>()); 

由于缺乏对自动装配支持的,你最终会与这些比较尴尬注册,这很快就会导致构建根目录的维护噩梦,但这与您的问题无关;-)

您通常应该尽量避免注册时出现歧义。在你的情况下,你有一个单一的接口,它做两件事(连接到两个数据库)。除非这两个数据库共享完全相同的模型中,每个数据库应该得到自己的接口(如果这两个实现并不互换,你会违反Liskov substitution principle):

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 question

随着Funq,你的配置然后将这个样子:

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

这两个新的接口和两个类并切换到MovieService没赢你很多,因为Funq不支持自动接线。你将是一个手动将所有东西连接在一起的人。但是,当您切换到确实支持自动布线的框架时,此设计允许容器注入正确的依赖关系而没有问题,因为没有关于要注入什么的讨论。

+1

谢谢你的详细解答。这正是我所寻找的。 – 2012-01-07 20:39:38

+5

注意:ServiceStack确实支持Funq.Container的自动布线 - 请参阅我的答案。 – mythz 2012-01-09 20:48:21

+1

@Steven如果数据库共享相同的模型会怎么样?即多租户 – 2014-10-01 12:18:50

11

虽然Funq不支持自动布线,ServiceStack的实现呢。 ServiceStack的最新版本包括Funq.Container重载:

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

所以在史蒂芬的例子中,你也可以这样做:

container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>(); 

,它会自动注册的依赖你。

+0

服务框架实现具有这样的功能非常奇怪。这看起来像是一个IoC容器的功能,而不是ServiceStack。 – Steven 2012-01-09 21:25:40

+1

同意,我很久以前在Funq的邮件列表中发布了它,但没有任何结果http://funq.codeplex.com/workitem/2158 – mythz 2012-01-09 21:32:05

+2

Funq框架似乎已经放弃很长一段时间了。为什么不切换到Simple Injector作为ServiceStack的默认IoC框架?由于ServiceStack似乎是一个高性能框架,Simple Injector非常适合,因为它是该领域最快的IoC框架。我认为ServiceStack真的很好,顺便说一句。 – Steven 2012-01-10 08:42:58

1

尝试使用存储库模式而不是此IoC(这会使事情不必要地复杂化)。上面的代码似乎不起作用。怀疑事情已经改变。我还不清楚注册IDbConnectionFactory如何神奇地填充IDbConnection属性。会喜欢关于这个的一些解释。 如果有人曾经使用ServiceStack IoC容器得到这个工作,那么我很想看看如何。更新SS文档会非常有益(我很乐意这样做)

+0

关于IDbConnectionFactory,您可以参考ServiceStack OrmLite代码:public virtual IDbConnection Db {get {return this.db (this.db = OrmLiteConnectionFactoryExtensions.Open(this.TryResolve ())); }} – labilbe 2013-10-15 11:59:33

3

以为我会在这里花2美分,但我意识到这个问题已经很老了。我想访问一个交易数据库,并从ServiceStack日志记录数据库,这是我怎么会从AppHostBase配置做()方法​​:

  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”打开一个连接时使用但我可以通过以下服务明确地访问日志DB:

 using (var db = DbFactory.Open("LoggingDB")) 
     { 
      db.Save(...); 
     } 
相关问题