2013-01-02 45 views
17

我目前正在開發一個項目,在該項目中,我們正在將舊數據集,存儲過程WinForm應用程序轉換爲使用實體框架,以便新網站可以訪問相同的對象模型和存儲庫。使用Ninject和實體框架在WinForms中進行依賴注入

無論如何,我正試圖在表單中實現依賴注入,以便我們可以使用模擬存儲庫進行單元測試。我使用Ninject是因爲我之前在MVC網站中使用過這個簡單的理由,但是試圖在WinForm應用程序中實現這一點的證明是有問題的,至少可以說是因爲在WinForms中缺乏關於DI的信息而受到更多的阻礙網絡。

到目前爲止,我已經創建了Ninject工廠和存儲庫,但是我沒有太多的運氣將存儲庫注入到表單中。

因此,任何人都可以幫助我或提出任何建議嗎?

下面我有我的部分代碼,這可能有助於:

Ninject廠:

public class NinjectFactory : NinjectModule 
{ 
    private IKernel _ninjectKernel; 

    public NinjectFactory() 
    { 
     _ninjectKernel = new StandardKernel(); 
    } 

    public override void Load() 
    { 
     _ninjectKernel.Bind(typeof(IRepository<>)).To(typeof(GenericRepository<>)); 
     _ninjectKernel.Bind(typeof(IProductionRepository)).To(typeof(ProductionRepository)); 
    } 
} 

形式庫:

Public Class TaskForm 
    Inherits BaseBusinessDialogForm 

    Private _repository As TaskRepository 
    Private _task As Production.Task = Nothing 

    Public Sub New(ByVal task As Production.Task) 

     InitializeComponent() 

     _repository = New TaskRepository(ConnectString) 

     If task.TaskID = 0 Then 
      _task = task 
     Else 
      _task = _repository.GetByID(task.TaskID) 
     End If 

     MyBase.BusinessObject = _task 
     Me.TaskBindingSource.DataSource = MyBase.BusinessObject 

    End Sub 

類,啓動其持有上述MDI窗體形式:

Dim kernel As IKernel = New StandardKernel(New NinjectFactory()) 
''Dim kernel As IKernel = New StandardKernel(New NinjectFactoryTest()) 
mfrmMDI = kernel.Get(Of Forms.MDI)() 

Application.DoEvents() 
mfrmMDI.ShowDialog() 

我明白我的問題有點含糊,但我不確定問題出在哪裏或我需要完成什麼。

非常感謝

+0

你有VB和C#的混合,將純粹在C#上有答案可以嗎? –

+0

對不同語言的混淆,直接來自項目代碼。舊的東西是在VB中,而在C#中是新的東西,惱人的是至少可以說! – XN16

回答

31

您創建組合根作爲您的決議的一個入口點。您將INjectModule作爲參數傳遞,以便您可以對其進行配置,以進行不同的測試。 Composition Root的好處之一是,並非所有的程序集都依賴於NInject,並且您將有一個單獨的點來更改解析邏輯。當你可能會改變IoC容器或者在將來引入一些動態攔截時,它確實是一個很酷的模式。

public class CompositionRoot 
{ 
    private static IKernel _ninjectKernel; 

    public static void Wire(INinjectModule module) 
    { 
     _ninjectKernel = new StandardKernel(module); 
    } 

    public static T Resolve<T>() 
    { 
     return _ninjectKernel.Get<T>(); 
    } 
} 

你的模塊應該是這樣

public class ApplicationModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind(typeof(IRepository<>)).To(typeof(GenericRepository<>)); 
    } 
} 

在main方法傳遞ApplicationModule作爲參數,並解決Form1並啓動它。

[STAThread] 
static void Main() 
{ 
    CompositionRoot.Wire(new ApplicationModule()); 

    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 

    Application.Run(CompositionRoot.Resolve<Form1>()); 
} 

Form1構造函數傳遞所需的庫與特定的封閉泛型參數

public partial class Form1 : Form 
{ 
    private IRepository<Process> _processRepository; 

    public Form1(IRepository<Process> productionRepository) 
    { 
     this._processRepository = productionRepository;   
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     MessageBox.Show(_processRepository.ToString()); 
    } 
} 

你的資料庫可能會非常複雜,但我不會添加任何功能,而不是ToString()方法,以便對他們來說,我們可以看到依賴關係是否被正確解析。請注意,存儲庫上沒有任何屬性。

public interface IRepository<T> 
{ 
} 

public class GenericRepository<T> : IRepository<T> 
{ 
    public override string ToString() 
    { 
     return "MyRepository with type : "+typeof(T).Name; 
    } 
} 

現在,當你運行你的應用程序,你會看到,所有已連接好和消息框顯示一個封閉的類型Process

enter image description here

+0

非常感謝,我已成功實現了您的示例版本。 – XN16

+2

我認爲你錯過了組合根的意圖。你的「組合根」實際上是一個服務定位器,通常被認爲是一個反模式。真正的合成根是運行應用程序的對象圖中的「頂級」對象,應該是您明確向內核請求的唯一對象(不包括工廠)。當根構造時,或通過工廠實例化時,其他所有內容都應通過注入來解決。 – FMM

+0

我的'CompositionRoot'不是服務定位器。 'Form1'請'IRepository '作爲構造函數參數,而不是'CompositionRoot'。 'CompositionRoot'在應用程序的開始處解析一個** complete **對象圖。你不需要從內核中調用'CompositionRoot',而是從'CompositionRoot'中查詢頂層對象,它爲你提供了一個完整的解析對象圖。 –