IoC之Ninject

一、Ninject安装

Ninject是一个轻量级的开源的DI容器,可以通过Nuget直接安装:

二、Ninject的简单使用

模型代码:

//计算器接口
public interface ICalculator
{
        decimal GetTotalValue(IEnumerable<Product> products);
}
//计算器实现类
public class LinqValueCalculator: IValueCalculator
{
        public decimal GetTotalValue(IEnumerable<Product> products)
     {
            return products.Sum(p => p.Price);
      }
}
//购物车
public class ShoppingCart
{
        //计算器
        private ICalculator calc;
        public ShoppingCart(ICalculator calcParam)
        {
            calc = calcParam;
        }
        public IEnumerable<Product> Products { get; set; }
        //算出商品价格
        public decimal CalcProductTotal()
        {
            return calc.GetTotalValue(Products);
        }
}

Ninject的简单使用:

 1    public class HomeController : Controller
 2     {
 3         Product[] products ={
 4                new Product{Name="kayak",Category="WaterSports",Price=275M},
 5                new Product{Name="lifejacket",Category="WaterSports",Price=48.95M},
 6                new Product{Name="soccer ball",Category="soccer",Price=19.50M},
 7                new Product{Name="corner flag",Category="soccer",Price=34.95M}};
 8         // GET: Home
 9        
10         public ActionResult Index()
11         {
12             //获取一个ninject内核对象,该对象负责解析依赖项和创建实例
13              IKernel ninjectKernel = new StandardKernel();
14             //注册服务,当我们需要ICalculator实例的时候,获取的是一个Calculator的实例
15              ninjectKernel.Bind<ICalculator>().To<Calculator>();
16             //获取实例
17             ICalculator calc= ninjectKernel.Get<ICalculator>();
18 
19             //ICalculator calc = new Calculator();使用IoC容器就不用直接new了
20             ShoppingCart cart = new ShoppingCart(calc) { Products = products };
21             decimal total = cart.CalcProductTotal();
22             return View(total);
23         }
24     }

三、Ninject的封装使用

第一步:创建依赖项解析器

服务解析器用于注册服务, IDependencyResolver 接口在System.Mvc命名空间下

 1         public class NinjectResolver : IDependencyResolver
 2     {
 3         private IKernel kernel;
 4         public NinjectResolver()
 5         {
 6             kernel = new Ninject.StandardKernel();
 7             AddBindings();
 8         }
 9         //获取服务实现类实例,没有合适的绑定是返回null
10         public object GetService(Type serviceType)
11         {
12             return kernel.TryGet(serviceType);
13         }
14         //当接口绑定多个服务实现类,可以使用getAll
15         public IEnumerable<object> GetServices(Type serviceType)
16         {
17             return kernel.GetAll(serviceType);
18         }
19 
20         private void AddBindings()
21         {
22             kernel.Bind<ICalculator>().To<LinqValueCalculator>();
23             //...这里注册服务
24         }
25     }

第二步:注册依赖项解析器

创建了一个实现IDependencyResolver接口的实现是不够的,我们需要告诉MVC框架使用它

方法1:在MVC5中可以通过在APP_Start文件下的NinjectWebCommon.cs文件来注册依赖项解析器

private static void ResisterServices(IKernel kernel){
    System.Web.Mvc.DependencyResolver.SetResolver(new NinjectResolver();
}

方法2:在global文件中添加注册

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
             //在这里添加
            System.Web.Mvc.DependencyResolver.SetResolver(new NinjectResolver());
        }

第三步:重构Controller

 1     public class HomeController : Controller
 2     {
 3         Product[] products ={
 4                new Product{Name="kayak",Category="WaterSports",Price=275M},
 5                new Product{Name="lifejacket",Category="WaterSports",Price=48.95M},
 6                new Product{Name="soccer ball",Category="soccer",Price=19.50M},
 7                new Product{Name="corner flag",Category="soccer",Price=34.95M}};
 8         ICalculator calc;//重构改动1
 9         public HomeController(ICalculator calcParam)//重构改动2
10         {
11             calc = calcParam;
12         }
13         public ActionResult Index()
14         {
15             ShoppingCart cart = new ShoppingCart(calc) { Products = products };
16             decimal total = cart.CalcProductTotal();
17             return View(total);
18         }
19     }

四、Ninject的一些补充

Ninject中有一些很好用的功能,这里只列出几种常用的:

4.1 依赖项链

  一句话解释就是解析依赖项的依赖项,一个栗子,当计算器类(ICalculator的实现类)依赖于一个打折类,当创建HomeController时,要解析HomeController的依赖LinqValueCalculator,而LinqValueCalculator又依赖于打折类FlexibleDiscountHelper打折类,那么Ninject能在创建HomeController时将FlexibleDiscountHelper也解析出来,打折服务(IDiscountHelper)和一些打折类代码如下:

namespace EssentialTools.Models
{
    //打折服务
    public interface IDiscountHelper
    {
        decimal ApplyDiscount(decimal totalParm);
    }
    //默认打折类
    public class DefaultDiscountHelper : IDiscountHelper
    {
        public decimal DiscountSize { get; set; }
        public decimal ApplyDiscount(decimal totalParm)
        {
            return totalParm - DiscountSize / 100M * totalParm;
        }
    }
    /// <summary>
    /// 弹性打折类,100元以上折扣70%,少于100元折扣25%
    /// </summary>
    public class FlexibleDiscountHelper : IDiscountHelper
    {
        public decimal ApplyDiscount(decimal totalParm)
        {
            decimal discount = totalParm > 100 ? 70 : 25;
            return totalParm - discount / 100M * totalParm;
        }
    }
    /// <summary>
    /// 最小打折类,大于100元打9折,10~100元之间减5元,10元以下无优惠
    /// </summary>
    public class MinimunDiscountHelper : IDiscountHelper
    {
        public decimal ApplyDiscount(decimal totalParm)
        {
            if (totalParm < 0)
            {
                throw new ArgumentOutOfRangeException();
            }
            else if (totalParm > 100)
            {
                return totalParm * 0.9M;
            }
            else if (10 <= totalParm && totalParm <= 100)
            {
                return totalParm - 5;
            }
            else
            {
                return totalParm;
            }
        }
    }
}

修改LinqValueCalculator为:

    //Linq计算器,用于计算商品总价
    public class LinqValueCalculator:ICalculator
    {
        private IDiscountHelper discounter;//打折
        public LinqValueCalculator(IDiscountHelper discountParm)//计算器依赖于打折类
        {
            discounter = discountParm;
        }
        public decimal ValueProducts(IEnumerable<Product> products){
            return discounter.ApplyDiscount(products.Sum(p => p.Price));
        }
    }

使用Ninject注册打折服务:

        private void AddBindings()
        {
            kernel.Bind<ICalculator>().To<LinqValueCalculator>();
            kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize",50M);//默认打折类打5折
            kernel.Bind<IDiscountHelper>().To<MinimunDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();//给LinqValueCalculator注入打折服务时,解析FlexibleDiscountHelper
        }

完成以上步骤后,不必更改HomeController中代码,运行程序即可,在程序创建HomeController的实例时,Ninject会将所有的依赖项都解析出来。

4.2  解析依赖项时传入属性值或构造器参数

//1.注入依赖项,给属性赋值。实例:注册默认打折类(DefaultDiscount)到打折服务(IDiscount),默认打折类的属性DiscountSize的值0.5(五折)
kernel.Bind<IDiscount>().To<DefaultDiscount>().WithPropertyValue("DiscountSize",0.5);
//2.注入依赖项时给构造器参数传值。还是上边的例子,如果DiscountSize不是DefaultDiscount的属性,而是构造函数的参数则使用下边代码进行赋值
kernel.Bind<IDiscount>().To<DefaultDiscount>().WithConstructorArgument("DiscountSize",0.5);

4.3   使用条件绑定

//当总价小于100时,选择的打折服务是默认打折类
kernel.Bind<IDiscount>().To<DefaultDiscount>().When(total<100);
//当为LinqValueCalcutor计算器类注入打折服务时,打折服务选择Linqdiscount
kernel.Bind<IDiscount>().To<MinimunDiscountHelper>.WhenInjectedInto<LinqValueCalcutor>();

4.4   设置对象作用域

Niject中对象作用域的内容很多,这里只列出几种常用的方法

1 kernel.Bind<IA>().To<A>().InTransientScope();//每个依赖项一个实例默认的
2 kernel.Bind<IA>().To<A>().InSingletonScope();//整个应用程序一个实例,单例
3 kernel.Bind<IA>().To<A>().InThreadScope();//每个线程一个实例
4 kernel.Bind<IA>().To<A>().InRequestScope();//每个请求一个实例

参考文献:

  本文参考的书籍是《精通ASP.NET MVC5》中文版,想了解更多内容的话可以参考这本经典的MVC教程。

原文地址:https://www.cnblogs.com/wyy1234/p/9295576.html