本文章不介绍控制反转和依赖注入的定义,主要是通过一个具体事例是说明如何使用Ninject进行依赖注入,在此在对控制反转模式的目的做一个简单的介绍,为了降低组件之间的耦合程度我们一般采用在两个代码块之间引入抽象层或者把选择抽象实现的责任移到消费者类的外部两种方式来实现。而控制反转模式就是把依赖的创建移动到使用这些依赖的类的外部。
一、准备事例项目,首先创建一个MVC项目
1、创建模型类Product.cs、LinqValueCaculator.cs、ShopCart.cs和接口IValueCalculator.cs。其中Product.cs类用于描述产品的相关属性,接口IValueCalculator用来计算Product对象集合的总价,LinqValueCaculator.cs类用于具体实现IValueCalculator接口。ShoppingCart.cs类用于表示Product对象的集合,并且使用LinqValueCalulator来确定总价。代码如下
Product.cs类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;namespace EssentialTools.Models
{
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
}
IValueCalculator接口代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;namespace EssentialTools.Models
{
public interface IValueCalculator
{
decimal ValueProducts(IEnumerable<Product> products);
}
}
LinqValueCalculator.cs类:
namespace EssentialTools.Models
{
public class LinqValueCalculator : IValueCalculator
{public decimal ValueProducts(IEnumerable<Product> products)
{
return products.Sum(p => p.Price);
}}
}
ShoppingCart.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;namespace EssentialTools.Models
{
public class ShoppingCart
{
private IValueCalculator calc;public ShoppingCart(IValueCalculator calcParam)
{
calc = calcParam;
}public IEnumerable<Product> Products { get; set; }
public decimal CalculateProductTotal()
{
return calc.ValueProducts(Products);
}
}
}
2、添加HomeController控制器
using EssentialTools.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace EssentialTools.Controllers
{
public class HomeController : Controller
{
private IValueCalculator calc;
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}
};
// GET: Home
public ActionResult Index()
{
IValueCalculator calc = new LinqValueCalculator();
ShoppingCart cart = new ShoppingCart(calc) { Products = products };decimal totalValue= cart.CalculateProductTotal();
return View(totalValue);
}
}
}
3、添加视图,该视图主要用来显示产品集合的总价
@model decimal
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Value</title>
</head>
<body>
<div>
Total value is $@Model
</div>
</body>
</html>
二、第一步我们完成了事例代码的准备,第二步完成Ninject的安装
1、在Visual Studio中依次选择“工具”—“NuGet包管理器”—“程序包管理控制台”,以打开NuGet命令行
2、依次按照以下命令进行安装
Install-Package Ninject -version 3.0.1.10
Install-Package Ninject.Web.Common -version 3.0.0.7
Install-Package Ninject.MVC3 -version 3.0.0.6
三、建立MVC的依赖项注入。完成Ninject的安装之后,然后需要依次进行创建依赖项解析器、注册依赖项解析器和重构Home控制器来完成MVC的依赖注入。
1、创建依赖项解析器
首先创建一个Infrastructure的文件夹然后在改文件夹下创建一个名为NinjectDependencyResolver.cs的类文件,完成后增加代码。
NinjectDependencyResolver.cs代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using EssentialTools.Models;
using Ninject;namespace EssentialTools.Infrastructure
{
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
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>() ;
}
}
}
2、注册依赖项解析器
使用NuGet添加Ninject包后系统会在App_Start文件夹中创建一个名称为NinjectWebCommon.cs的类文件。修改该文件中的RegisterServices方法完成依赖解析器的注册,代码如下:
[assembly: WebActivator.PreApplicationStartMethod(typeof(EssentialTools.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(EssentialTools.App_Start.NinjectWebCommon), "Stop")]namespace EssentialTools.App_Start
{
using System;
using System.Web;using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(new
EssentialTools.Infrastructure.NinjectDependencyResolver(kernel));
}
}
}
3、重新Home控制器,依赖注入完成后,我们需要重新改写Home控制器代码以解除HomeController控制器和LinqValueCalculator类之间的紧耦合。
using EssentialTools.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ninject;
namespace EssentialTools.Controllers
{
public class HomeController : Controller
{
private IValueCalculator calc;
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}
};public HomeController(IValueCalculator calaParam, IValueCalculator calc2)
{
calc = calaParam;
}// GET: Home
public ActionResult Index()
{
ShoppingCart cart = new ShoppingCart(calc) { Products = products };
decimal totalValue = cart.CalculateProductTotal();
return View(totalValue);
}
}
}
至此,整个使用Ninject进行依赖注入的流程已经结束。