还是那几句话:

学无止境,精益求精

十年河东,十年河西,莫欺少年穷

学历代表你的过去,能力代表你的现在,学习代表你的将来

上篇博客介绍了依赖注入的三种方式:构造方法注入,属性注入,接口注入!详情请参考:学习 IOC 设计模式前必读:依赖注入的三种实现

本篇继续介绍IOC和DI的故事

今天将以一个具体的IOC框架来介绍,Ninject 框架:

1、Ninject简介

  Ninject是基于.Net平台的依赖注入框架,它能够将应用程序分离成一个个高内聚、低耦合(loosely-coupled, highly-cohesive)的模块,然后以一种灵活的方式组织起来。Ninject可以使代码变得更容易编写、重用、测试和修改。

  Ninject官方网址为:http://www.ninject.org/ 。

2、项目引用Ninject.DLL 及 Ninject.Extensions.Xml.DLL

  关于程序集的引用大家可自行下载DLL文件也可以通过NuGet管理器来下载,在此不作说明。

3、项目实例

  和上篇博客一样,我们通过具体例子来分享Ninject框架

  本篇继续采用上篇博客(学习 IOC 设计模式前必读:依赖注入的三种实现)案例进行说明,如下:

  首先,如同上篇博客背景一样,项目最初要求采用的是SqlServer数据库搭建,后来老板要求改为MySql数据库,再后来,老板要求改为Access数据库,再后来,老板又要求改为Oracle数据库,总之,这个老板的事很多...(请参考上篇博客)

  现在要求你设计一个解决方案,方便项目的扩展,你应该怎么设计?

  Ninject闪亮登场:

  首先,我们创建一个接口类,如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace ConsoleNinject.Interface
  8. {
  9. public interface IDataAccess
  10. {
  11. void Add();
  12. }
  13. }

由于项目将来很可能变更数据库,因此,在项目构建之初我们应先将常用的数据库实现,如下:

Access数据库实现如下:

  1. using ConsoleNinject.Interface;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7.  
  8. namespace ConsoleNinject.DAL
  9. {
  10. public class AccessDAL : IDataAccess
  11. {
  12. public void Add()
  13. {
  14. Console.WriteLine("在ACCESS数据库中添加一条订单");
  15. }
  16. }
  17. }

MySql数据库实现如下

  1. using ConsoleNinject.Interface;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7.  
  8. namespace ConsoleNinject.DAL
  9. {
  10. public class MySqlDAL : IDataAccess
  11. {
  12. public void Add()
  13. {
  14. Console.WriteLine("在MYSQL数据库中添加一条订单");
  15. }
  16. }
  17. }

Oracle数据库实现如下:

  1. using ConsoleNinject.Interface;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7.  
  8. namespace ConsoleNinject.DAL
  9. {
  10. public class OracleDAL : IDataAccess
  11. {
  12. public void Add()
  13. {
  14. Console.WriteLine("在Oracle数据库中添加一条订单");
  15. }
  16. }
  17. }

SqlServer数据库实现如下:

  1. using ConsoleNinject.Interface;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7.  
  8. namespace ConsoleNinject.DAL
  9. {
  10. public class SqlServerDAL : IDataAccess
  11. {
  12. public void Add()
  13. {
  14. Console.WriteLine("在SQLSERVER数据库中添加一条订单");
  15. }
  16. }
  17. }

截止到现在,数据库层面的设计基本完成,现在我们来模仿一个下订单的类,分别采用构造方法注入和属性注入的方式,如下:

  1. using ConsoleNinject.Interface;
  2. using Ninject;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8.  
  9. namespace ConsoleNinject.UI
  10. {
  11. /// <summary>
  12. /// 订单类-通过构造方法注入
  13. /// </summary>
  14. public class OrderCls
  15. {
  16. private IDataAccess _datadal;
  17.  
  18. [Inject]
  19. public OrderCls(IDataAccess DataDAL)
  20. {
  21. _datadal = DataDAL;
  22. }
  23.  
  24. public void Add()
  25. {
  26. _datadal.Add();
  27. }
  28. }
  29.  
  30. /// <summary>
  31. /// 订单类-通过属性注入
  32. /// </summary>
  33. public class OrderCls_SX
  34. {
  35. private IDataAccess _datadal;
  36.  
  37. /// <summary>
  38. /// 属性注入
  39. /// </summary>
  40. public IDataAccess DataDAL
  41. {
  42. get
  43. {
  44. return _datadal;
  45. }
  46. set
  47. {
  48. _datadal = value;
  49. }
  50. }
  51.  
  52. public void Add()
  53. {
  54. _datadal.Add();
  55. }
  56. }
  57. }

最后,便是利用NinJect框架来构建依赖关系并输出结果,如下:

  1. using ConsoleNinject.DAL;
  2. using ConsoleNinject.Interface;
  3. using Ninject.Modules;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9.  
  10. namespace ConsoleNinject.UI
  11. {
  12. public class DataModule : NinjectModule
  13. {
  14. public override void Load()
  15. {
  16. Bind<IDataAccess>().To<AccessDAL>();
  17. Bind<IDataAccess>().To<MySqlDAL>();
  18. Bind<IDataAccess>().To<OracleDAL>();
  19. Bind<IDataAccess>().To<SqlServerDAL>();
  20. //
  21. Bind<OrderCls>().ToSelf();
  22. Bind<OrderCls_SX>().ToSelf();
  23. }
  24.  
  25. }
  26. }

上述代码,注意继承的类及Bind()...To()方法,使用这个方法来确定类与接口之间的依赖关系

输出代码如下:

  1. using ConsoleNinject.DAL;
  2. using Ninject;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8.  
  9. namespace ConsoleNinject.UI
  10. {
  11. class Program
  12. {
  13. static void Main(string[] args)
  14. {
  15. IKernel kernal = new StandardKernel(new DataModule());
  16. OrderCls mysql = new OrderCls(kernal.Get<MySqlDAL>()); // 构造函数注入
  17. mysql.Add();
  18. //
  19. OrderCls access = new OrderCls(kernal.Get<AccessDAL>()); // 构造函数注入
  20. access.Add();
  21. //
  22. OrderCls_SX oracle = new OrderCls_SX();
  23. OracleDAL oracledal = new OracleDAL();//属性依赖注入
  24. oracle.DataDAL = oracledal;
  25. oracledal.Add();
  26. //
  27. OrderCls_SX sqlserver = new OrderCls_SX();
  28. SqlServerDAL sqlserverdal = new SqlServerDAL();//属性依赖注入
  29. sqlserver.DataDAL = sqlserverdal;
  30. sqlserverdal.Add();
  31. //
  32. Console.ReadLine();
  33. }
  34. }
  35. }

这样,整个项目就设计完了,四种数据库都实现了!老板应该可以闭嘴了,即使再要求换成另外一个类型的数据库,我们也不怕,只需增加相应的DAL层及依赖关系Module并修改输出即可!

这样,就基本符合设计模式的开闭原则,OrderCls代码内的业务逻辑代码是无需修改的!

但是,上述的方式仍然属于手动注入的方式,如何能做到动态配置呢?换句话说,如何能通过修改配置文件来完成动态配置呢?

Ninject是支持通过XML配置文件来实现动态注入的,这时需要引入:Ninject.Extensions.Xml.DLL

首先创建XML配置文件:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <module name="ServiceModule">
  3. <bind name="IDataAccess" service="ConsoleNinject.Interface.IDataAccess,ConsoleNinject.Interface" to="ConsoleNinject.DAL.SqlServerDAL,ConsoleNinject.DAL"/>
  4. </module>

其次,书写Ninject XML 读取类,如下:

  1. using Ninject;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Ninject.Extensions.Xml;
  8. using System.Xml.Linq;
  9.  
  10. namespace ConsoleNinject.UI
  11. {
  12. public class XMLModuleContext : IDisposable
  13. {
  14. public XMLModuleContext()
  15. {
  16. var settings = new NinjectSettings() { LoadExtensions = false };
  17. Kernel = new StandardKernel(settings, new XmlExtensionModule());
  18. }
  19.  
  20. protected IKernel Kernel { get; private set; }
  21.  
  22. public void Dispose()
  23. {
  24. this.Kernel.Dispose();
  25. }
  26. }
  27. public class NinjectXMServiceLModule : XMLModuleContext
  28. {
  29. private static readonly NinjectXMServiceLModule instance = new NinjectXMServiceLModule();
  30. protected readonly XmlModule module = null;
  31. public NinjectXMServiceLModule()
  32. {
  33. var path = "D:/VS2012测试项目/ConsoleNinject/ConsoleNinject/Config/Ninject.xml"; //路径写死了 绝对路径
  34. Kernel.Load(path);
  35. module = Kernel.GetModules().OfType<XmlModule>().Single();
  36. }
  37.  
  38. public static IKernel GetKernel()
  39. {
  40. return instance.Kernel;
  41. }
  42. }
  43. }

最后,输出端代码如下:

  1. using ConsoleNinject.DAL;
  2. using ConsoleNinject.Interface;
  3. using Ninject;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9.  
  10. namespace ConsoleNinject.UI
  11. {
  12. class Program
  13. {
  14. static void Main(string[] args)
  15. {
  16. #region 手动注入
  17. IKernel kernal = new StandardKernel(new DataModule());
  18. OrderCls mysql = new OrderCls(kernal.Get<MySqlDAL>()); // 构造函数注入
  19. mysql.Add();
  20. //
  21. OrderCls access = new OrderCls(kernal.Get<AccessDAL>()); // 构造函数注入
  22. access.Add();
  23. //
  24. OrderCls_SX oracle = new OrderCls_SX();
  25. OracleDAL oracledal = new OracleDAL();//属性依赖注入
  26. oracle.DataDAL = oracledal;
  27. oracledal.Add();
  28. //
  29. OrderCls_SX sqlserver = new OrderCls_SX();
  30. SqlServerDAL sqlserverdal = new SqlServerDAL();//属性依赖注入
  31. sqlserver.DataDAL = sqlserverdal;
  32. sqlserverdal.Add();
  33. //
  34. #endregion
  35.  
  36. #region 通过配置文件动态注入,说白了就是依赖关系写在了配置文件中
  37. var kernel = NinjectXMServiceLModule.GetKernel();
  38. var database = kernel.Get<IDataAccess>();
  39. OrderCls ordcls = new OrderCls(database);
  40. Console.WriteLine("我是通过配置文件确定的依赖关系!");
  41. ordcls.Add();
  42. #endregion
  43. Console.ReadLine();
  44. }
  45. }
  46. }

OK,上述便是整个Ninject的代码实现,下面转载下Ninject常用的方法:

(1)Bind<T1>().To<T2>()

其实就是接口IKernel的方法,把某个类绑定到某个接口,T1代表的就是接口或者抽象类,而T2代表的就是其实现类

例如:

  1. IKernel ninjectKernel = new StandardKernel();
  2. ninjectKernel.Bind<ILogger>().To<FileLogger>();

(2)Get<ISomeInterface>()

其实就是得到某个接口的实例,例如下面的栗子就是得到ILogger的实例FileLogger:

  1. ILogger myLogger= ninjectKernel.Get<ILogger>();

(3)Bind<T1>() .To<T2>(). WithPropertyValue("SomeProprity", value);

其实就是在绑定接口的实例时,同时给实例NinjectTester的属性赋值,例如:

  1. ninjectKernel.Bind<ITester>().To<NinjectTester>().WithPropertyValue("_Message", "这是一个属性值注入");

(4)ninjectKernel.Bind<T1>().To<T2>(). WithConstructorArgument("someParam", value);

其实就是说我们可以为实例的构造方法所用的参数赋值,例如:

  1. public class DefalutDiscountHelper : IDiscountHelper
  2. {
  3. private decimal discountRate;
  4. public decimal DiscountSize { get; set; }
  5. public DefalutDiscountHelper(decimal discountParam)
  6. {
  7. discountRate = discountParam;
  8. }
  9.  
  10. public decimal ApplyDiscount(decimal totalParam)
  11. {
  12. return (totalParam - (discountRate / 100M * totalParam));
  13. }
  14. }
  1. ninjectKernel.Bind<IDiscountHelper>().To<DefalutDiscountHelper>().WithConstructorArgument("discountParam", 50M);

(5)Bind<T1>().ToConstant()

这个方法的意思是绑定到某个已经存在的常量,例如:

  1. StudentRepository sr = new StudentRepository();
  2. ninjectKernel.Bind<IStudentRepository>().ToConstant(sr);

(6)Bind<T1>().ToSelf()

这个方法意思是绑定到自身,但是这个绑定的对象只能是具体类,不能是抽象类。为什么要自身绑定呢?其实也就是为了能够利用Ninject解析对象本身而已。例如:

  1. ninjectKernel.Bind<StudentRepository>().ToSelf();
    StudentRepository sr = ninjectKernel.Get<StudentRepository>();

(7)Bind<T1>().To<T2>().WhenInjectedInto<instance>()

这个方法是条件绑定,就是说只有当注入的对象是某个对象的实例时才会将绑定的接口进行实例化

  1. ninjectKernel.Bind<IValueCalculater>().To<IterativeValueCalculatgor>().WhenInjectedInto<LimitShoppingCart>();

(8)Bind<T1>().To<T2>().InTransientScope()或者Bind<T1>().To<T2>().InSingletonScope()

这个方法是为绑定的对象指明生命周期其实

  1. ninjectKernel.Bind<IStudentRepository>().To<StudentRepository>().InTransientScope();
  2. //每次调用创建新实例
    ninjectKernel.Bind<IStudentRepository>().To<StudentRepository>().InSingletonScope();
    //每次调用是同一个实例

(9)Load()方法

这里的Load()方法其实是抽象类Ninject.Modules.NinjectModule的一个抽象方法,通过重写Load()方法可以对相关接口和类进行集中绑定,例如:

  1. public class MyModule : Ninject.Modules.NinjectModule
  2. {
  3. public override void Load()
  4. {
  5. Bind<ILogger>().To<FileLogger>();
  6. Bind<ITester>().To<NinjectTester>();
  7. }
  8. }

这是通过Load()方法绑定之后的完整代码:

  1. private static IKernel kernel = new StandardKernel(new MyModule());
  2. static void Main(string[] args)
  3. {
  4. ITester tester = kernel.Get<ITester>(); // 因为是链式解析,因此只解析ITester即可,其它依赖的东东都会顺带解析
    tester.Test();
  5. Console.Read();
  6. }

(10)Inject属性

在Inject中,我们可以通过在构造函数、属性和字段上加 Inject特性指定注入的属性、方法和字段等,例如下面的栗子,MessageDB有两个构造函数:int和object类型的。现在我们已经为int型的指定了Inject特性,因此在注入的时候选择的就是int型的构造函数;如果没有在构造函数上指定Inject特性,则默认选择第一个构造函数:

  1. public class MessageDB : IMessage
  2. {
  3. public MessageDB() { }
  4. public MessageDB(object msg)
  5. {
  6. Console.WriteLine("使用了object 参数构造:{0}", msg);
  7. }
  8.  
  9. [Inject]
  10. public MessageDB(int msg)
  11. {
  12. Console.WriteLine("使用了int 参数构造:{0}", msg);
  13. }
  14.  
  15. public string GetMsgNumber()
  16. {
  17. return "从数据中读取消息号!";
  18. }
  19. }

关于MVC中如何使用Ninject?本篇不作说明,我相信只要懂了基础,其他的Ninject的使用应该会手到擒来!

项目下载地址:https://files.cnblogs.com/files/chenwolong/ConsoleNinject.zip

@陈卧龙的博客

IOC框架之Ninject 简介的更多相关文章

  1. 轻量级IOC框架:Ninject

    Ninject 学习杂记 - liucy 时间2014-03-08 00:26:00 博客园-所有随笔区原文  http://www.cnblogs.com/liucy1898/p/3587455.h ...

  2. 轻量级IOC框架:Ninject (上)

    前言 前段时间看Mvc最佳实践时,认识了一个轻量级的IOC框架:Ninject.通过google搜索发现它是一个开源项目,最新源代码地址是:http://github.com/enkari/ninje ...

  3. 轻量级IOC框架:Ninject (下)

    一,创建依赖链(Chains of Dependency) 当我们向Ninject请求创建一个类型时,Ninject会去检查该类型和其他类型之间的耦合关系.如果有额外的依赖,Ninject也会解析它们 ...

  4. IOC框架Ninject实践总结

    原文地址:http://www.cnblogs.com/jeffwongishandsome/archive/2012/04/15/2450462.html IOC框架Ninject实践总结 一.控制 ...

  5. 国人编写的开源 .net Ioc 框架——My.Ioc 简介

    My.Ioc 是作者开发的一款开源 IoC/DI 框架,下载地址在此处.它具有下面一些特点: 高效 在实现手段上,My.Ioc 通过使用泛型.缓存.动态生成代码.延迟注册.尽量使用抽象类而非接口等方式 ...

  6. 轻量级IoC框架Ninject.NET搭建

    说在之前的话 IOC的概念相信大家比较熟悉了,习惯性称之为依赖注入或控制反转,园子里对基于MVC平台IOC设计模式已经相当多了,但大家都只知道应该怎么应用一个IOC模式,比如Ninject, Unit ...

  7. 使用Microsoft的IoC框架:Unity来对.NET应用进行解耦

    1.IoC/DI简介 IoC 即 Inversion of Control,DI 即 Dependency Injection,前一个中文含义为控制反转,后一个译为依赖注入,可以理解成一种编程模式,详 ...

  8. 各大主流.Net的IOC框架性能测试比较

    Autofac下载地址:http://code.google.com/p/autofac/ Castle Windsor下载地址:http://sourceforge.net/projects/cas ...

  9. 主流IOC框架测验(.NET)

    上一篇中,我简单介绍了下Autofac的使用,有人希望能有个性能上的测试,考虑到有那么多的IOC框架,而主流的有:Castle Windsor.微软企业库中的Unity.Spring.NET.Stru ...

随机推荐

  1. id、name、setter方法注入、构造方法注入、工厂方法注入、注解注入、方法注入、方法替换、Web作用域、普通bean引用Web作用域的bean

    spring IoC的id和name id的命名需要满足XML对id的命名规范,必须以字母开始,后面可以是字母.数字.连字符.下画线.句号.冒号等等号,但逗号和空格是非法的.如果用户确实希望用一些特殊 ...

  2. JavaWeb:jsp

    本文内容: JSP的介绍 jsp的使用 EL表达式 JSTL的使用 首发日期:2018-06-18 JSP的介绍: JSP全称Java Server Pages. 与静态网页格式的html不同的是,j ...

  3. Centos7安装搭建Bugzilla 5.0

    1.安装准备: Centos7保证网络连通,如果网络不能连通,可通过配置yum源使用代理服务. vim /etc/yum.conf # The proxy server - proxy server: ...

  4. C#获取H5页面上传图片代码

    基于上一篇的H5压缩上传图片,由于图片是以二进制字符流blob的形式传过来的,所以应该想将其转成bytes类型再进行转换 public void ProcessRequest(HttpContext ...

  5. 四则运算 Java 姚康友,黎扬乐

    github项目传送门:https://github.com/yaokangyou/arithmetic 项目要求 功能列表 [完成] 使用 -n 参数控制生成题目的个数 [完成] 使用 -r 参数控 ...

  6. sass @function,@for,@mixin 的应用

    项目前提: 不同的汽车显示不同的图片,一共9种汽车:每种汽车显示不同状态的图片,一共6种状态,所以一共会有54张图片 后台接口返回汽车种类分别为:1-9,汽车状态分别为:0-5 项目需求: 根据后台返 ...

  7. Linux进程ID号--Linux进程的管理与调度(三)【转】

    Linux 内核使用 task_struct 数据结构来关联所有与进程有关的数据和结构,Linux 内核所有涉及到进程和程序的所有算法都是围绕该数据结构建立的,是内核中最重要的数据结构之一. 该数据结 ...

  8. centos7下安装指定版本mysql5.7.23

    现在mysql版本已经到MySQL 8.0(GA)稳定版本了,所以需求是想简单又快速在centos7下安装指定版本例如MySQL 5.7(GA)版本有下面这种方法 首先需要到mysql官网这里下载对应 ...

  9. python学习--Django虚拟环境搭建

    一 . 为什么选择搭建虚拟环境 搭建一个只对本次项目有用的虚拟环境,而不影响主环境 二 . 安装前准备 #    1. 安装 python #    2. 安装virtualenvwrapper #  ...

  10. ELK-logstash-6.3.2部署

    Logstash 是一款强大的数据处理工具,它可以实现数据传输,格式处理,格式化输出,还有强大的插件功能,常用于日志处理. 1. logstash部署 [yun@mini04 software]$ p ...