IOC框架Ninject实践总结
原文地址:http://www.cnblogs.com/jeffwongishandsome/archive/2012/04/15/2450462.html
IOC框架Ninject实践总结
一、控制反转和依赖注入
Ninject是一个轻量级的基于.Net平台的依赖注入(IOC)框架。所谓的IOC,即控制反转(Inversion of Control),它是一个经典的面向对象编程法则,它的作用主要是用来帮助应用程序解耦,并把程序分离成一个个松耦合高内聚的模块。控制反转还有一个名字叫依赖注入(Dependency Injection),简称DI。
二、快速无xml配置注入
1、定义应用程序Module
using LogService;
using LogService.Impl;
using Ninject.Modules;
using NinjectApp.Warrior;
using NinjectApp.Weapon; namespace NinjectApp
{
internal class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<ILogService>().To<DbLogService>(); Bind<IWeapon>().To<Sword>().InSingletonScope();
//Bind<IWeapon>().To<Shuriken>(); Bind<Shuriken>().ToSelf().WhenInjectedInto<IWeapon>(); Bind<IWarrior>().To<FootSoldier>();
//Bind<IWarrior>().To<Samurai>(); }
}
}
2、手动调用服务
/// <summary>
/// 手动注入
/// </summary>
static void InjectManual()
{
using (var kernel = new StandardKernel(module))
{
var dbLogger = kernel.Get<ILogService>();
dbLogger.AppendLog("hello world"); var weapon = kernel.Get<IWeapon>();
Console.WriteLine(weapon.GetType());
Console.WriteLine(weapon.Name); //weapon = kernel.Get<Shuriken>();
//Console.WriteLine(weapon.GetType());
//Console.WriteLine(weapon.Name); var weapon1 = kernel.Get<IWeapon>();
Console.WriteLine(weapon1.GetType());
Console.WriteLine(weapon1.Name); Console.WriteLine(object.ReferenceEquals(weapon, weapon1)); var warrior = kernel.Get<IWarrior>();
Console.WriteLine(warrior.GetType());
} }
注:Ninject的绑定对象作用域有多种,本文的demo中有具体的单元测试,具体可以直接查看源码或者参考官方文档。。
三、配置文件注入
通过Ninject的xml扩展,可以实现传统的类似于Spring.net、Unity等IOC容器的注入方式。
1、配置文件

<?xml version="1.0" encoding="utf-8" ?>
<module name="ServiceModule">
<bind name="Txtlog" service="LogService.ILogService,LogService" to="LogService.Impl.TxtLogService,LogService"/>
<!--<bind name="Dblog" service="LogService.ILogService,LogService" to="LogService.Impl.DbLogService,LogService"/>-->
<bind name="Sword" service="NinjectApp.Weapon.IWeapon,NinjectApp" to="NinjectApp.Weapon.Sword,NinjectApp"/>
<bind name="FootSoldier" service="NinjectApp.Warrior.IWarrior,NinjectApp" to="NinjectApp.Warrior.FootSoldier,NinjectApp"/>
</module>

2、利用扩展加载服务
using System.Collections.Generic;
using System.Xml.Linq;
using Ninject;
using Ninject.Extensions.Xml;
using Ninject.Extensions.Xml.Handlers; namespace NinjectApp
{
public class XmlModuleContext
{
protected readonly IKernel kernel;
protected readonly IDictionary<string, IXmlElementHandler> elementHandlers; public XmlModuleContext()
{
kernel = new StandardKernel();
elementHandlers = new Dictionary<string, IXmlElementHandler> { { "bind", new BindElementHandler(kernel) } };
}
} public class XmlServiceModule : XmlModuleContext
{
private static readonly XmlServiceModule instance = new XmlServiceModule(); protected readonly XmlModule module = null; public XmlServiceModule()
{
var document = XDocument.Load("Config/NinjectServiceModule.config");
module = new XmlModule(document.Element("module"), elementHandlers);
module.OnLoad(kernel);
} public static IKernel GetKernel()
{
return instance.kernel;
}
}
}
3、调用服务
/// <summary>
/// 通过xml配置注入
/// </summary>
static void InjectByConfig()
{
var kernel = XmlServiceModule.GetKernel();
var logger = kernel.Get<ILogService>();
Console.WriteLine(logger.GetType());
logger.AppendLog("hello world"); var weapon = kernel.Get<IWeapon>();
Console.WriteLine(weapon.GetType());
Console.WriteLine(weapon.Name); var warrior = kernel.Get<IWarrior>();
Console.WriteLine(warrior.GetType());
}
虽然配置注入看上去更容易扩展应对外部变化,但是项目庞大臃肿之后,配置文件并不好管理。固然有一些可视化的工具,但是仍然容易出现偏差。Ninject最擅长的基本注入功能就是无配置简单快速注入,达到free yourself from xml的目的,对于一般的中小型应用程序完全可以零配置。
四、MVC项目的依赖注入
通过Ninject的MVC扩展可以轻松实现MVC项目的依赖注入。
1、NinjectHttpApplication
在Global.asax.cs文件里重新定义MvcApplication继承自NinjectHttpApplication,重写OnApplicationStarted事件和CreateKernel方法:
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IUserService>().To<UserInfoService>();
kernel.Bind<ILogService>().To<TxtLogService>();
//kernel.Bind<ILogService>().To<TxtLogService>().InSingletonScope();//单例
return kernel;
}
2、通过构造函数或者属性或者Module实现注入
(1)、Controller实现注入
a、构造函数注入
private readonly IUserService userService = null;
public AccountController(IUserService userService)
{
this.userService = userService;
//var userInfo = userService.GetCurrentUser();//do sth
}
b、属性注入
定义属性,加上Inject特性即可实现注入。
[Inject]
public IUserService CurrentUserService { get; set; }
c、module注入
定义Module:
using LogService;
using LogService.Impl;
using Ninject.Modules;
using UserService;
using UserService.Impl; namespace MVCApp.Helper
{
internal class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<ILogService>().To<TxtLogService>();
Bind<IUserService>().To<UserInfoService>();
}
}
}
接着调用即可:
using (var kernel = new StandardKernel(new ServiceModule()))
{
var logger = kernel.Get<ILogService>();
}
(2)、自定义Attribute实现注入
using System.Web.Mvc;
using LogService;
using Ninject; namespace MVCApp.Helper
{
/// <summary>
/// 异常处理特性
/// </summary>
public class ExceptionHandleAttribute : HandleErrorAttribute
{
[Inject]
public ILogService Logger { get; set; } public override void OnException(ExceptionContext filterContext)
{
Logger.AppendLog(filterContext.Exception.ToString());//记录日志
}
}
}
和Controller非常相似,示例使用属性加上Inject特性的方式实现注入,其他注入方式略过。
到这里,你应该已经可以看到,这可以算是web应用程序中非常干净利落的注入方式,简单的令人发指。
五、组合还是继承
通过IOC框架实现服务依赖注入本来不难,但是这里或多或少会牵扯到一个问题:注入服务调用是使用组合还是继承?
举例来说,最基础的用户服务(或者日志服务),一般的web应用程序几乎每个控制器(或者页面)都或多或少和用户有关系。
问题来了,不同的控制器或者页面要调用用户服务该怎么做?
下面以MVC项目为例来说明一下通常的注入方法。
如你所知,通常的做法,所谓组合优于继承(继承被认为是一种强耦合),我们只要在需要调用服务的控制器中定义一个服务变量或者属性,通过构造函数注入,类似下面这样:
private readonly IUserService userService = null;
public AccountController(IUserService userService)
{
this.userService = userService;
}
然后在对应的Action中就可以调用用户服务了。
如果你的Controller很少,这种方式当然可以接受。但是,实际项目中控制器真的比较多的时候,有一些几乎每个控制器必然用到的公共服务,我们是不是不得不哼哧哼哧写很多构造函数实现依赖注入呢?
到这里,你一定想到,是啊,都调用一样的服务,几乎都类似的代码,重构吧!
最简单的方式,利用继承,集中在一个地方(通常就叫BaseController吧)写一次,
using System.Web.Mvc;
using LogService;
using Ninject;
using UserService;
using UserService.Model; namespace MVCApp.Helper
{
[ExceptionHandle]
public class BaseController : Controller
{
/// <summary>
/// 构造函数
/// </summary>
public BaseController()
{
if (CurrentLogService==null)
{
using (var kernel = new StandardKernel(new ServiceModule()))
{
var logger = kernel.Get<ILogService>();
logger.AppendLog("As you see,in constructor log service is not initilized by inject attribute.");
}
}
} protected UserInfo CurrentUser
{
get { return CurrentUserService.CurrentUser; }
} #region 服务 [Inject]
public IUserService CurrentUserService { get; set; } [Inject]
public ILogService CurrentLogService { get; set; } #endregion
}
}
然后,在相应的Controller下this点服务属性名调用一下,多么优雅干净简洁。但是这种方式有一点需要特别需要注意,在Controller的构造函数里调用服务初始化一些数据可能不能让你那么随心所欲,因为在构造函数内,服务还没有初始化。
如上代码所示,通过Inject特性实现服务注入,通过继承实现公共服务调用,不管哪种表现形式的应用程序都可以使用,有AOP和继承的世界看上去是多么美好啊。当然了,具体使用哪种方式好每个人肯定都有自己的看法,实际项目中,我们通常选择组合和继承相结合的方式,这样就可以兼顾两者的优点实现注入。
最后还有几个困扰人的问题需要思考:如何划分服务?服务和服务之间是否应该依赖注入?如果仅仅是在表现层实现依赖注入,难道不觉得IOC的作用有点太酱油了吗?
domo下载:NinjectApp
参考:http://www.ninject.org/wiki.html
http://www.cnblogs.com/cnmaxu/archive/2011/10/25/2224375.html
IOC框架Ninject实践总结的更多相关文章
- 轻量级IoC框架Ninject.NET搭建
说在之前的话 IOC的概念相信大家比较熟悉了,习惯性称之为依赖注入或控制反转,园子里对基于MVC平台IOC设计模式已经相当多了,但大家都只知道应该怎么应用一个IOC模式,比如Ninject, Unit ...
- 轻量级IOC框架:Ninject (上)
前言 前段时间看Mvc最佳实践时,认识了一个轻量级的IOC框架:Ninject.通过google搜索发现它是一个开源项目,最新源代码地址是:http://github.com/enkari/ninje ...
- 轻量级IOC框架:Ninject
Ninject 学习杂记 - liucy 时间2014-03-08 00:26:00 博客园-所有随笔区原文 http://www.cnblogs.com/liucy1898/p/3587455.h ...
- IOC框架之Ninject 简介
还是那几句话: 学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 上篇博客介绍了依赖注入的三种方式:构造方法注入,属性注入,接口注入!详情请参考 ...
- ASP.NET MVC IOC 之Ninject攻略
ASP.NET MVC IOC 之Ninject攻略 一.为什么要使用Ninject? 很多其它类型的IOC容器过于依赖配置文件,老是配置,总感觉有点不爽,而且要使用assembly-qualifie ...
- IOC框架
一. IOC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机 ...
- 转:IOC框架
CSND上看了王泽滨的博客关于IOC的,觉得说的很透彻,地址为:http://blog.csdn.net/wanghao72214/article/details/3969594 1 IoC理论的背景 ...
- 各大主流.Net的IOC框架性能测试比较
Autofac下载地址:http://code.google.com/p/autofac/ Castle Windsor下载地址:http://sourceforge.net/projects/cas ...
- IoC框架(转载)
1 IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果 ...
随机推荐
- http://jingyan.baidu.com/article/08b6a591f0fafc14a9092275.html
http://jingyan.baidu.com/article/08b6a591f0fafc14a9092275.html http://jingyan.baidu.com/article/414e ...
- 李洪强iOS开发支付集成之微信支付
iOS开发支付集成之微信支付 微信支付也是需要签名的,也跟支付宝一样,可以在客户端签名,也可以在后台签名(当然,为了安全还是推荐在服务器上做签名,逻辑也比较好理解). 1 - 集成前首先要看看文档 开 ...
- 欧拉工程第66题:Diophantine equation
题目链接 脑补知识:佩尔方差 上面说的貌似很明白,最小的i,对应最小的解 然而我理解成,一个循环的解了,然后就是搞不对,后来,仔细看+手工推导发现了问题.i从0开始变量,知道第一个满足等式的解就是最小 ...
- LR_问题_脚本运行时提示没有参数化
问题描述 将loadrunner中的参数删除,并且删除脚本目录下对应的bak,执行脚本,出现下面的错误: “错误: 表“XX\phonenumbser.dat”不存在. [MsgId: ...
- mysql23个知识点
1.它是一种解释语言:写一句执行一句,不需要整体编译执行. 2.1.没有“ ”,字符串使用‘ '包含 3.一个表只有一个主键,但是一个主键可以是由多个字段组成的 组合键 4.实体完整性:实体就是指一条 ...
- 删除元素 不存在 NO 存在 输出余下元素
#include<stdio.h> #include<stdlib.h> #define N 5 #define NULL 0 #define OK 1 #define ERR ...
- GitHub最全的前端资源汇总仓库(包括前端学习、开发资源、求职面试等)
在GitHub上收集的最全的前端资源汇总(包括前端学习.前端开发资源.前端求职面试等) 个人结合github上各位大神分享的资源进行了简单的汇总整理,每一个条目下面都有丰富的资料,是前端学习.工作的好 ...
- PHP二位数组/多维数组 根据某个键值排序
$arr[$i]['FirstName'] = $d_first_name;$arr[$i]['MiddleName'] = $d_middle_name;$arr[$i]['LastName'] = ...
- iOS Objective-C对象模型及应用
前言 原创文章,转载请注明出自唐巧的技术博客. 本文主要介绍Objective-C对象模型的实现细节,以及Objective-C语言对象模型中对isa swizzling和method swizzli ...
- 深度分析Java的ClassLoader机制(源码级别)
写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoa ...