ASP.NET MVC如何知道要调用哪个控制器构造函数?

时间:2014-07-13 10:46:29

标签: asp.net-mvc asp.net-mvc-4 ninject

我目前正在启动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());

问题:

  1. ASP.NET MVC是如何知道要调用哪个控制器构造函数的?我假设它将调用默认构造函数,但没有一个,我尝试添加一个,仍然调用带参数的构造函数。

  2. ASP.NET MVC是如何将IValueCalculator传递给构造函数的?

2 个答案:

答案 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的构造函数。如果构造函数具有依赖关系,则将使用相同的机制注入它们。