2012-09-16 115 views
2

您好我正在使用Ninject.MVC Nuget包與我的MVC3應用程序,我有一些構造函數注入的當前綁定設置。Ninject.MVC構造函數注入其中注入對象的構造函數採用參數

private static void RegisterServices(IKernel kernel) 
    { 
     kernel.Bind<IUnitOfWork>().To<ERSUnitOfWork>(); 
     kernel.Bind<IRepository<Recipe>>().To<GenericRepository<Recipe>>(); 
    } 

我控制器例子如下:

public class RecipesController : Controller 
{ 
    private readonly IUnitOfWork unitOfWork; 
    private readonly ERSDbContext context; 
    private readonly IRepository<Recipe> recipeRepository; 

    public RecipesController(IUnitOfWork unitOfWork, IRepository<Recipe> recipeRepository) 
    { 
     this.context = new ERSDbContext(); 
     this.unitOfWork = unitOfWork; 
     this.recipeRepository = recipeRepository; 
    } 
} 

我想從控制器中刪除私有的DbContext財產和通過新的ERSDbContext()來ERSUnitOfWork和GenericRepository的構造爲部分Ninject正在執行的構造函數注入,但最好在控制器內部保持ERSDbContext類的初始化?

任何幫助你如何做到這一點將不勝感激。謝謝

我有點希望它不需要我的NinjectWebCommon類必須創建DbContext,我想要在控制器中初始化。

+1

DbContexts創建起來非常便宜。沒有「初始化」。該對象已創建,但未打開任何連接或構建複雜結構。當第一次調用DbContext時,DbContext使用延遲初始化。 –

+0

相關:http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why。 – Steven

+0

我以前見過這個相關的帖子,我看到了像我的一個簡單項目的方法注入的例子。我的問題是知道如何將其實現到我當前的示例中。 – Pricey

回答

3

這是你如何抽象你的依賴關係的問題。

因爲你想擁有,當你創建你DbContext例如在控制,你應該有一個工廠,將創建特定類型的DbContext情況下,像這樣:

public interface IDbContextFactory 
{ 
    T CreateDbContext<T>() where T : DbContext; 
} 

(請注意,如果您的DI框架處理類型參數的通用接口上還算不錯,那麼你可以用IDbContextFactory interface去,將其與實體框架5)

介紹如果你永遠只需要創建一個廣告類型DbContext實例EFAULT,參數構造函數,你可以定義你的界面,如下所示:

public interface IDbContextFactory 
{ 
    T CreateDbContext<T>() where T : DbContext, new(); 
} 

,然後定義像這樣實現:

public class DbContextFactory : IDbContextFactory 
{ 

    #region Implementation of IDbContextFactory 

    public T CreateDbContext<T>() where T : DbContext, new() 
    { 
     // Create a new instance of T and return. 
     return new T(); 
    } 

    #endregion 
} 

如果需要調用不同的構造函數,那麼你刪除new() constraint並且必須使用反射調用(或者,您可以創建一個lambda表達式並根據T的類型對其進行高速緩存)以創建鍵入的DbContext

從那裏您將IDbContextFactory合同與您的實施相關聯,並將IDbContextFactory實施注入您的課程,就像您將使用其他任何接口一樣。

+0

我沒有看到這個好處,除非你想單元測試,在這種情況下,你可以讓你的DbContext從一個通用接口派生(這更直接)。增加一個額外的工廠似乎沒有意義。 –

+0

@MystereMan在問題的最後一句中明確指出,創作的控制是OP想要的東西。僅僅約束自己並不會給OP這個控制權。如果你的控制器中有更長時間運行的方法,那麼'DbContext'的生命週期就會被默認擴展(除非你早先處理它)。如果方法代碼的一小部分依賴於'DbContext',最好儘快創建並拆除。讓這樣的事情在方法/控制器的生命中保持開放通常不是好主意。 – casperOne

+0

@MystereMan另外請注意,我並不是主張類型化的'DbContext'從接口派生,關鍵是要有一個工廠爲你生成它們。你可能不想爲'DbContext'使用默認的無參數構造函數。 – casperOne

1

這是依賴注入的好處之一,它會自動解析所有構造函數參數及其相關的構造函數參數。它爲你做了這一切,只需要定義對象的映射。

所以你的情況,你只是這樣做:

kerel.Bind<ERSDbContext>().ToSelf(); 

然後,你可以添加ERSDbContext您UOW和回購,你是好。

如果你想單元測試的東西,那麼你就需要抽象的背景下不知何故,無論是作爲casperOne提到或我提到(其中你讓你的DbContext從通用接口派生),然後做到這一點,而不是:

kernel.Bind<IDbContext>().To<ERSDbContext>(); 

使用DI的好處之一是它控制對象的生命週期。如果您將DbContext的構建推遲到DI容器的外部,那麼您必須手動管理其生命週期,而不是允許DI容器根據生命週期策略(例如在請求結束時自動銷燬它)來管理它。

我認爲延遲創建上下文沒有任何可衡量的好處。我認爲你正在做過早的優化。

+0

我遇到的問題是,如果其中一個節點正在執行保存,那麼在同一個HTTP請求的範圍內不能有多個DbContext。這就是爲什麼我創建了UoW類。原來我的背景是在UoW和我的回購,但那是糟糕的設計。現在我已經把它們分開了,並且使用我的回購查詢以及我的任何保存的UoW,就像你說的,我必須確保UoW處理上下文的處置。現在我處於需要將相同的環境傳遞給UoW和回購站的情況。 – Pricey

+0

與此相關的錯誤是「不能定義兩個對象之間的關係,因爲它們連接到不同的ObjectContext對象」,這是我在使用上面的示例時仍然可以獲得的東西,不幸的是。感謝您解釋更多關於DbContext,這有助於。 – Pricey

+0

對不起,我的例子沒有顯示它,但有時我在同一個控制器操作中使用多個存儲庫,這是我的問題。 – Pricey

0

由於我的併發問題,我暫時取消了工廠的使用,而我正在使用這種方法,因爲我的時間很短。

kernel.Bind<ERSDbContext>().ToSelf().InRequestScope(); 

然後在我的UoW和GenericRepository中構造函數需要一個ERSDbContext類型參數。

我想稍後改進這種方法,但現在這工作。

+0

我真的沒有看到這個問題,因爲這正是它的目的。我認爲你的代碼味道更多的是關於你如何設計你的UoW和Repository。您的存儲庫應該將UoW作爲構造函數參數,並且您的UoW應該將上下文作爲構造函數參數。 –

+0

出於利益您爲什麼認爲存儲庫應該將UoW作爲構造函數參數?不應該將它們保持分開,並且存儲庫應該沒有關於如何提交事務的概念?只做查詢?我在想的是如何使DbContext成爲一個我可以傳遞的接口..但是我現在所擁有的並不算太壞,因爲Ninject正在處理依賴關係,並且我還假設將它添加到HttpContext Items集合中以使其請求作用域? – Pricey

+0

不,Ninject不會將它添加到HttpContext.Items,而是掛鉤到RequestEnd事件中,然後處理所有事情。至於爲什麼倉庫應該採用UoW取決於你的外牆的工作方式。您仍然可以將UoW傳遞給存儲庫,並且還可以依賴於您的業務對象中的UoW。這樣你可以控制提交。 –