• 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教程。

  • 相关阅读:
    爬虫的基础知识(贰)
    Django内置标签
    WPF ToggleButton Style
    编写一个简单的COM组件
    C# 调用DOS 命令
    【转】 C#中检查网络是否连通的二种方法
    c++中的类型转换
    COM笔记-包容与聚合
    windows笔记-在可执行文件或DLL的多个实例之间共享静态数据
    编程之路
  • 原文地址:https://www.cnblogs.com/wyy1234/p/9295576.html
Copyright © 2020-2023  润新知