我目前正在启动ASP.NET MVC 4,在我正在阅读的书中,作者介绍了Ninject的依赖注入。他创建了一个自定义依赖项解析器(我不完全理解它是如何工作的,但我认为它的用途是轻松管理依赖项解析)。
这是控制器代码:
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());
问题:
ASP.NET MVC是如何知道要调用哪个控制器构造函数的?我假设它将调用默认构造函数,但没有一个,我尝试添加一个,仍然调用带参数的构造函数。
ASP.NET MVC是如何将IValueCalculator传递给构造函数的?
答案 0 :(得分:5)
ASP.NET MVC是如何知道的......
它通过询问DependencyResolver
来了解。当必须创建控制器时,MVC将调用GetService()
。
default MVC resolver仅处理无参数构造函数,但在您的情况下,您已经分配了自定义解析程序,GetService()
调用将被转发到NInject的IKernel.TryGet(Type)
。
NInject将搜索类型HomeController
及其构造函数,并找到具有IValueCalculator
参数的那个。
在AddBindings()
方法中,每当需要LinqValueCalculator
时,您已指示NInject注入IValueCalculator
,所以它会这样做,使用反射实例化类型并将初始化的控制器返回给MVC
答案 1 :(得分:4)
这是文档(https://github.com/ninject/ninject/wiki/Dependency-Injection-With-Ninject)的引用:
当被要求实例化一个对象时,Ninject会查看该类型的对象 可用的公共构造函数并选择最多的构造函数 它知道如何解决的参数 - 或者无参数的参数 不是任何合适的(有一个属性可以用于 覆盖这个 - 参见构造函数注入的细节)。
以及此处的另一个引用(https://github.com/ninject/ninject/wiki/Injection-Patterns):
如果构造函数具有[Inject]属性,则使用它(但如果你是 将属性应用于多个,Ninject会抛出一个 检测到运行时的NotSupportedException。
如果没有构造函数具有[Inject]属性,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
的构造函数。如果构造函数具有依赖关系,则将使用相同的机制注入它们。