2014-07-13 78 views
0

我目前正在啓動ASP.NET MVC 4,在我正在閱讀的書中,作者介紹了Ninject進行依賴注入。他創建了一個自定義的依賴關係解析器(我不完全理解它是如何工作的,但我認爲它的用途是輕鬆管理依賴關係解析)。ASP.NET MVC如何知道調用哪個控制器構造函數?

這裏是控制器代碼:

public class HomeController : Controller 
{ 
    private Product[] products = { 
     new Product {Name = "Kayak", Category = "Watersports", Price = 275M}, 
     new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, 
     new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, 
     new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M} 
    }; 

    private IValueCalculator calc; 
    public HomeController(IValueCalculator calcParam) 
    { 
     calc = calcParam; 
    } 

    public ActionResult Index() 
    { 
     ShoppingCart cart = new ShoppingCart(calc) { Products = products }; 
     decimal totalValue = cart.CalculateProductTotal(); 
     return View(totalValue); 
    } 
} 

而且自定義依賴解析器:

public class NinjectDependencyResolver : IDependencyResolver 
{ 
    private IKernel kernel; 
    public NinjectDependencyResolver() 
    { 
     kernel = new StandardKernel(); 
     AddBindings(); 
    } 

    public object GetService(Type serviceType) 
    { 
     return kernel.TryGet(serviceType); 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     return kernel.GetAll(serviceType); 
    } 

    private void AddBindings() 
    { 
     kernel.Bind<IValueCalculator>().To<LinqValueCalculator>(); 
    } 
} 

在的Application_Start(),解析器設置:

DependencyResolver.SetResolver(new NinjectDependencyResolver()); 

問題:

  1. ASP.NET MVC是如何知道要調用哪個控制器構造函數的?我認爲它將調用默認的構造函數,但沒有一個,我嘗試添加一個,仍然調用了帶參數的構造函數。

  2. ASP.NET MVC是如何將IValueCalculator傳遞給構造函數的?

+0

通過定義的路由配置。 –

+0

Pro ASP.NET MVC 5! – Josh

回答

4

這是從文檔報價(https://github.com/ninject/ninject/wiki/Dependency-Injection-With-Ninject):

當記者問到實例化一個對象,Ninject會看類型的 提供公共的構造函數,並挑選一個與它知道最 參數如何解決 - 或無參數的如果 沒有任何合適的(有一個屬性可以用來覆蓋這個 - 請參閱構造函數注入的基本內容)。

,從這裏(https://github.com/ninject/ninject/wiki/Injection-Patterns)另一句名言:

如果構造函數有一個[進樣]屬性,它被用於(但如果你
應用屬性不止一個,Ninject會在檢測到時在運行時拋出
NotSupportedException)。

如果沒有構造函數具有[注入]屬性,則Ninject將選擇Ninject瞭解如何解析 的參數最多的參數。

如果沒有定義構造函數,Ninject會選擇默認的無參數構造函數(假設有一個構造函數)。

ASP.NET MVC是如何將IValueCalculator傳遞給構造函數的?

整個MVC管道使用控制器工廠來構建特定控制器的實例。控制器工廠裏面使用了DependencyResolver。這就是爲什麼依賴解析器是在應用程序啓動註冊:

DependencyResolver.SetResolver(new NinjectDependencyResolver()); 

正如我之前寫的,Ninject知道如何找到正確的構造函數,並用它來構建實例。它發現這個構造:

public HomeController(IValueCalculator calcParam) 

這裏依賴解析器來找到IValueCalculator實施,這被定義如下:

private void AddBindings() 
{ 
    kernel.Bind<IValueCalculator>().To<LinqValueCalculator>(); 
} 

Ninject這裏再次嘗試一個找到構造函數LinqValueCalculator類。如果構造函數具有依賴性,它們將使用相同的機制注入。

+0

所以Ninject的TryGet試圖實例化HomeController(我之前認爲我們需要在Ninject實例化之前註冊類型,比如IValueCalculator及其實現,我的理解是正確的)?如果我輸入的內容是正確的,正如你所說Ninject試圖使用它可以解決的大多數參數的構造函數實例化。如果我有兩個或更多具有相同參數數量的構造函數,Ninject知道如何解決?謝謝! –

+0

@g_b:你不必爲自己註冊類的類型。你必須註冊接口。我不記得Ninject如何在構造函數中使用相同數量的parateres。你通常應該避免它或使用[Inject]屬性指出正確的。 – LukLed

5

ASP.NET MVC怎麼知道......

它知道通過詢問DependencyResolver。必須創建控制器時,MVC將呼叫GetService()

default MVC resolver只處理parametersless構造函數,但在你的情況已指定自定義的解析器,其中GetService()的通話將被轉發到NInject的IKernel.TryGet(Type)

然後NInject將搜索類型HomeController及其構造函數,並將找到具有IValueCalculator參數的那個。

在你已指示NInject到每一個需要IValueCalculator時間注入LinqValueCalculatorAddBindings()方法,所以它這樣做,實例化使用反射類型,並返回初始化控制器MVC。

+0

謝謝,但一些問題。爲什麼它決定使用帶有IValueCalculator參數的HomeController構造函數?如果在我的AddBindings中,我有2個以上的綁定(IDiscountHelper,IExampleHelper),並且HomeController另外還有另外2個帶有單個參數的構造函數(一個接受IDiscountHelper,另一個接受IExampleHelper構造函數)。選擇哪一個作爲構造函數?另外,你可以指示我有關ASP.NET MVC如何使用DependencyResolver的資源嗎?我一直在瀏覽,但我似乎無法在互聯網上找到一個。 –

相關問題