ASP.NET MVC IOC 之Ninject攻略

一、为什么要使用Ninject?

很多其它类型的IOC容器过于依赖配置文件,老是配置,总感觉有点不爽,而且要使用assembly-qualified名称(也就是类型的全名)来进行定义,稍不注意就会因为打错字而令整个程序崩掉。Ninject是一个快如闪电、超轻量级的基于.Net平台的IOC容器,主要用来解决程序中模块的耦合问题,它的目的在于做到最少配置。因此如果你不喜欢配置,不喜欢重量级IOC框架,那么就用小苹果Ninject吧!

二、Ninject的使用

首先你必须获取Ninject,其官网下载地址:http://www.ninject.org,你也可以通过VS中的NuGet来加载Nniject,不论是哪种方式,最终的目的就是将 Ninject.dll 这个程序集引用到你的项目中。这样在你的项目中,如果想使用Ninject,只需添加其命名空间引用即可~

  1. using Ninject;

1Ninject入门

我们先定义一个记录日志的接口:

  1. public interface ILogger
  2. {
  3. void Write(string message);
  4. }

然后用文件记录日志方式和数据库记录日志方式分别实现这个接口,不过这里只是演示而已,所以并没有真正去实现这两个类,你懂的~

  1. public class FileLogger : ILogger
  2. {
  3. public void Write(string message)
  4. {
  5. Console.WriteLine(String.Format("文件记录日志:{0}", message));
  6. }
  7. }
  8.  
  9. public class DBLogger : ILogger
  10. {
  11. public void Write(string message)
  12. {
  13. Console.WriteLine(String.Format("数据库记录日志:{0}", message));
  14. }
  15. }

在Ninject中,我们可以通过重写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<ILogger>().To<DBLogger>();
  7. }
  8. }

具体调用方法:

  1. private static IKernel kernel = new StandardKernel(new MyModule());
  2. static void Main(string[] args)
  3. {
  4. ILogger logger = kernel.Get<ILogger>();//获取的是FileLogger
  5. logger.Write(" Hello Ninject!");
  6. Console.Read();
  7. }

没错,用Ninject进行依赖注入就是这么爽歪歪~

2、Ninject常用方法属性说明

这里我们使用构造函数注入一个栗子:

首先新建一个测试接口ITester与其实现类NinjectTester ,显然NinjectTester依赖于ILogger

  1. interface ITester
  2. {
  3. void Test();
  4. }
  5.  
  6. class NinjectTester:ITester
  7. {
  8. public string _Message{set;get;}

  9. private ILogger _logger;
  10. public NinjectTester(ILogger logger)
  11. {
  12. _logger = logger;
  13. }
  14. public void Test()
  15. {
  16. _logger.Write("Hello Ninject!");
  17. }
  18. }

下面就看看用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. }

3、Ninject能使用配置文件吗?

答案是肯定的,要不怎么说Ninject是可扩展的呢,必须可以,但是如果这样的话,你就没必要用Ninject了,因为这样又回到了繁琐的配置上面,还不如用其他的IOC容器来得方便,这里用的是Ninject的XML扩展,你可以通过下面的地址https://github.com/ninject/ninject.extensions.xml下载扩展组件,主要也就是Ninject.Extensions.Xml这个东东起的作用,这里不想详说,给个栗子了结:

(1)配置文件

 

(2)利用扩展加载服务

 

(3)调用服务

 

三、ASP.NET MVC与Ninject

说了这么多Ninject,主要还是想将其用到ASP.NET MVC的IOC中,其实很简单,大概就几个步骤搞定:

1、继承DefaultControllerFactory,重载GetControllerInstance方法,实现自己的NinjectControllerFactory类

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Mvc;
  6. using System.Web.Routing;
  7. using Ninject;
  8. using NinjectMvc.Models;
  9.  
  10. namespace NinjectMvc.Ioc
  11. {
  12. public class NinjectControllerFactory : DefaultControllerFactory
  13. {
  14. private IKernel ninjectKernel;
  15.  
  16. public NinjectControllerFactory()
  17. {
  18. ninjectKernel = new StandardKernel();
  19. AddBindings();
  20. }
  21.  
  22. protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  23. {
  24. return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
  25. }
  26.  
  27. private void AddBindings()
  28. {
  29. ninjectKernel.Bind<IStudentRepository>().To<StudentRepository>();
  30. }
  31. }
  32. }

2、在函数Application_Start() 注册自己的控制器工厂类

  1. public class MvcApplication : System.Web.HttpApplication
  2. {
  3. protected void Application_Start()
  4. {
  5. AreaRegistration.RegisterAllAreas();
  6.  
  7. WebApiConfig.Register(GlobalConfiguration.Configuration);
  8. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  9. RouteConfig.RegisterRoutes(RouteTable.Routes);
  10. BundleConfig.RegisterBundles(BundleTable.Bundles);
  11. AuthConfig.RegisterAuth();
  12.  
  13. ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
  14. //设置控制器工厂生产类为自己定义的NinjectControllerFactory
  15. }
  16. }

3、现在在你的MVC程序中注入依赖代码就ok了

(1)首先声明一个Student学生类

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5.  
  6. namespace NinjectMvc.Models
  7. {
  8. public class Student
  9. {
  10. public int Id { get; set; }
  11. public string Name { get; set; }
  12. public string Graduation { get; set; }
  13. public string School { get; set; }
  14. public string Major { get; set; }
  15. }
  16. }

(2)然后声明仓储接口和其实现

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace NinjectMvc.Models
  7. {
  8. public interface IStudentRepository
  9. {
  10. IEnumerable<Student> GetAll();
  11. Student Get(int id);
  12. Student Add(Student item);
  13. bool Update(Student item);
  14. bool Delete(int id);
  15. }
  16. }
 

(3)最后添加控制器StudentController,并注入依赖代码

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Mvc;
  6. using NinjectMvc.Models;
  7.  
  8. namespace NinjectMvc.Controllers
  9. {
  10. public class StudentController : Controller
  11. {
  12. readonly IStudentRepository repository;
  13. //构造器注入
  14. public StudentController(IStudentRepository repository)
  15. {
  16. this.repository = repository;
  17. }
  18.  
  19. public ActionResult Index()
  20. {
  21. var data = repository.GetAll();
  22. return View(data);
  23. }
  24.  
  25. }
  26. }

(4)最后为控制器StudentController的Index方法添加视图即可,这里不再详述,运行效果如下

总结

总的感觉来说,Ninject这个IOC容器给人的感觉还是蛮清爽的,我觉得它就是IOC里边的小清新,用简单的方式就能够处理复杂的系统依赖问题,而且它还能够扩展,因此我觉得从ASP.NET MVC 4往后开始它可能真正成为主流Ioc神器,关于Ninject的一些更深层次和更高级的功能有待以后进一步实践和研究,不管怎样,我觉得让它在你的项目里跑起来才是王道,因为这才是它存在的意义!
 
*将自己学习的点滴记录并分享出来,既能使自己得到成长,偶尔也能帮助一下别人,何乐而不为呢?如果这篇文章对你还有点用的话,希望帮忙推荐一下~

ASP.NET MVC IOC 之Ninject攻略的更多相关文章

  1. ASP.NET MVC IOC之Unity攻略

    ASP.NET MVC IOC之Unity攻略 一.你知道IOC与DI吗? 1.IOC(Inversion of Control )——控制反转 即依赖对象不在被依赖模块的类中直接通过new来获取 先 ...

  2. [转]ASP.NET MVC IOC 之AutoFac攻略

    本文转自:http://www.cnblogs.com/WeiGe/p/3871451.html 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用A ...

  3. ASP.NET MVC IOC 之AutoFac攻略

    一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用AutoFac的貌似更为普遍,于是捯饬了两天,发现这个东东确实是个高大上的IOC容器~ Autofa ...

  4. ASP.NET MVC Razor视图引擎攻略

    --引子 看下面一段MVC 2.0的代码. <%if (Model != null){%> <p><%=Model%></p><%}%>&l ...

  5. ASP.NET MVC IOC 之AutoFac

    ASP.NET MVC IOC 之AutoFac攻略 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用AutoFac的貌似更为普遍,于是捯饬了两天, ...

  6. ASP.NET没有魔法——ASP.NET MVC IoC

    之前的文章介绍了MVC如何通过ControllerFactory及ControllerActivator创建Controller,而Controller又是如何通过ControllerBase这个模板 ...

  7. ASP.NET MVC中使用Ninject

    ASP.NET MVC中使用Ninject 在[ASP.NET MVC 小牛之路]系列上一篇文章(依赖注入(DI)和Ninject)的末尾提到了在ASP.NET MVC中使用Ninject要做的两件事 ...

  8. ASP.NET MVC IOC依赖注入之Autofac系列(二)- WebForm当中应用

    上一章主要介绍了Autofac在MVC当中的具体应用,本章将继续简单的介绍下Autofac在普通的WebForm当中的使用. PS:目前本人还不知道WebForm页面的构造函数要如何注入,以下在Web ...

  9. Asp.net MVC 中使用 Ninject 实现依赖注入

    松耦合.针对抽象编程.不针对实现编程是面向对象设计的原则.依赖注入就是,在一个类的内部,不通过创建对象的实例而能够获得实现了某个公开接口的对象引用.所谓的控制反转也是相同的意思.把依赖的创建转移到了使 ...

随机推荐

  1. Linux内核分析(五)----字符设备驱动实现

    原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷, ...

  2. 求N!末尾的0的个数(找规律+递归)

    0\'s Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描写叙述 计算整数n!(n的阶乘)末尾有多少个0. 输入 第一行输入一个数T代 ...

  3. ubuntu14.04(64位置) ADB Not Responding

    今天装了一个很搞笑的比率Ubuntu14.04  还安装Android studio    写app   执行错误: Adb not responding. you can wait more or ...

  4. 使用newLISP由SMTPserver发送电子邮件

    直接使用的标准模块smtpx.lsp, smtp.lsp你可以不设置port,庭审后,没用. 以下是一个示例代码: #!/usr/bin/newlisp (set 'debug-flag true) ...

  5. redis安装和配置教程phpredis扩展安装测试

    作者:zhanhailiang 日期:2014-10-16 推荐阅读: Redis持久化策略 关于Redis很多其它资料阅读 1. 下载redis-2.8.17.tar.gz:http://downl ...

  6. SWOT分析是神马?

    SWOT分析是思维的工具来理解事物的方式.人生在世,作为一个独立的实体,不可避免地需要思考的问题.除非你是猪.猪比这更聪明.眠质量,都要完爆白领,蓝领和金领们. SWOT分析分为四个象限.我们用一头名 ...

  7. hdu 1533 Going Home 最小费用流

    构建地图非常easy bfs预处理地图.距离的成本 来源所有m建方,流程1费0 m所有H建方,流程1距离成本 H汇点建设成为各方.流程1费0 #include<cstdio> #inclu ...

  8. 安卓开发笔记——探索EventBus(转)

    1.关于EventBus: 组件通讯在Android开发中是不可避免的,随着业务需求的复杂化,代码中需要我们去处理的业务逻辑难度也不断增大.例如多个Fragment之间的数据传递,Service与Ac ...

  9. express: command not found.

    npm install -g express 可是不行.全局模式不行. With the release of Express 4.0.0 it looks like you need to do s ...

  10. Oracle语句优化1

    Oracle语句优化1 优化就是选择最有效的方法来执行SQL语句.Oracle优化器选择它认为最有效的     方法来执行SQL语句.         1. IS   NULL和IS   NOT   ...