2012-01-06 67 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(...); 
     } 
相關問題