2012-08-16 29 views
13

我的應用程序包含許多後端程序集(包括實體框架數據存儲庫層),這些後端程序集由許多前端程序集(包括Windows服務和一個MVC3網絡應用程序)。何處在多層應用程序中定位Ninject模塊

我對Ninject綁定過程的理解是,每個包含注入類型的程序集都應該包含一個Ninject模塊,該模塊定義了這些類型的默認綁定。然後將定義的模塊集加載到消費組件的Ninject內核中。

但是,我遇到了問題,因爲所需的綁定範圍並不總是一致的。例如,我的MVC項目需要綁定到數據上下文InRequestScope,而Windows服務綁定到相同的類InThreadScope

我明顯可以通過將所有模塊重新放置到前端項目中來解決這個問題,併爲每個使用場景維護每個模塊的單獨副本,但這看起來很詭異,因爲它複製了多個項目中的大部分模塊內容。

模塊應該在多層應用程序中的位置是否有最佳實踐,以及如何將這與需要約束項目之間的差異進行協調?

非常感謝您的建議,

+0

另請參閱http://stackoverflow.com/questions/1699197/how-do-you-organise-your-ninject-modules(IIRC此Q是一個dup,但這是我現在得到的最好的) – 2012-08-18 07:01:07

+0

謝謝魯本。你說得對,這兩個問題有很多共同之處。我特別喜歡你將運行時參數傳遞到駐留在支持程序集中的模塊中的建議 - 非常靈活。 – 2012-08-19 10:51:38

+0

嗯;這是前段時間(沒有試圖以任何方式拉我的答案)。我可能在字面意思是*將參數*傳回給當天 - 一般來說,我會盡可能通過接口嘗試這樣做。另外,那是http://manning.com/seemann之前,它減少了你在DI體系結構中會令人困惑的問題數量 - 明確地說,購買它不會有問題。 – 2012-08-19 20:14:58

回答

12

對於具有單個應用程序的解決方案,一般建議是在應用程序項目(您的Web應用程序或Web服務項目)中註冊您的容器。對於Web應用程序,這通常是Global.asax Application_Start。在這個你把所有東西連接在一起的地方在DI術語中被稱爲Composition Root

對於多應用程序解決方案,每個應用程序項目仍然有一個組合根。這必須是,因爲每個應用程序都有其獨特的配置。另一方面,重複的代碼總是不好的。當你引入新的抽象時,你不想改變三個地方。

訣竅是將所有註冊向下移動到項目層次結構中。例如,您可以定義一個取決於您的業務層組件(及以下)的單個「引導程序集」,並讓它擁有所有不會更改的程序集的所有註冊。然後,應用程序的組成根可以使用該程序集來獲取默認註冊並將其擴展爲特定於應用程序的依賴項。

這樣的事情可能是這樣的:

// MVC Composition root 
public static void Bootstrap() 
{ 
    var container = new Container(); 

    // Default registrations 
    BusinessLayerBootstrapper.Bootstrap(container); 

    // Application specific registrations 
    container.Bind<IUserContext>().To<AspNetUserContext>(); 

    DependencyResolver.Current = 
     new ContainerDependencyResolver(container); 
} 

// Windows Service Composition root 
public static void Bootstrap() 
{ 
    var container = new Container(); 

    // Default registrations 
    BusinessLayerBootstrapper.Bootstrap(container); 

    // Application specific registrations 
    container.Bind<IUserContext>().To<SystemUserContext>() 
     .SingleScoped(); 

    // Store somewhere. 
    Bootstrapper.Container = container; 
} 

// In the BL bootstrap assembly 
public static class BusinessLayerBootstrapper 
{ 
    public static void Bootstrap(Container container) 
    { 
     container.Bind<IDepenency>().To<RealThing>(); 
     // etc 
    } 
} 

雖然你不需要有一個單獨的引導程序組件(你可以把在BL本身的代碼),這可以讓你保持你的業務圖層組件不受任何依賴於您的容器的影響。

另請注意,我只是調用靜態Bootstrap()方法,而不是使用(Ninject)模塊。我試圖讓我的答案獨立於框架,因爲你的問題是一般的,所有的DI框架的建議都是一樣的。但是,如果需要,當然可以使用Ninject模塊功能。

6

關於作用域一個MVC應用程序需要有不同的CompositionRoot比windows服務。我建議你儘可能地通過功能模塊(對於應用程序不可知的部分)和所有其他綁定直接在MVC或WindowsService項目的CompositionRoot中進行組織。

另一個非常好的方法是定義一組通用的約定,它可以幫助您在幾行中表達最具約束力的問題。因此,你的應用程序可能有以下來綁定:

MVC應用程序

Bind(c => c.FromAssemblyContaining<IRepository>() 
      .SelectAllClasses() 
      .InheritedFrom<IRepository>() 
      .Configure(b => b.InRequestScope())); 

你的Windows服務應用程序

Bind(c => c.FromAssemblyContaining<IRepository>() 
      .SelectAllClasses() 
      .InheritedFrom<IRepository>() 
      .Configure(b => b.InThreadScope())); 

在我看來與功能導向的結構結合點的慣例做法是最乾淨的一個。

相關問題