说在之前的话

IOC的概念相信大家比较熟悉了,习惯性称之为依赖注入或控制反转,园子里对基于MVC平台IOC设计模式已经相当多了,但大家都只知道应该怎么应用一个IOC模式,比如Ninject, Unity等常用框架,并不清楚为什么要用它,它们之间有什么区别,换句话说在实际应用中的横向对比的文章比较少,本文旨在抛砖引玉,欢迎大家讨论

Ninject模式实现

VS工具提供了很方便的ninject模式引入,新建一个asp.net mvc项目后,执行几行命令就即可

1.添加Ninject。工具-->Nuget程序包管理器-->程序包管理器控制台,输入下面的命令:

Install-Package Ninject -version 3.0.1.10
Install-Package Ninject.Web.Common -version 3.0.0.7
Install-Package Ninject.MVC3 -Version 3.0.0.6

分别引用了

Minject

Ninject.Web.Common

Ninject.Web.MVC

Ninject模式下,有两种常用的方式实现,一种是通过Activitor激活Controller的方式,另一种方式MVC5推荐的DependencyResolver方式

首先做好准备工作,假设有一个Employee实体类

public class Employee
{
[Display(Name="ID")]
public string Id { get; private set; }
[Display(Name = "姓名")]
public string Name { get; private set; }
[Display(Name = "性别")]
public string Gender { get; private set; }
[Display(Name = "出生日期")]
[DataType(DataType.Date)]
public DateTime BirthDate { get; private set; }
[Display(Name = "部门")]
public string Department { get; private set; } public Employee(string id, string name, string gender, DateTime birthDate, string department)
{
this.Id = id;
this.Name = name;
this.Gender = gender;
this.BirthDate = birthDate;
this.Department = department;
}
}

对实现类提供的操作服务

public interface IEmployeeRepository
{
IEnumerable<Employee> GetEmployees(string id = "");
}

添加对服务的实现

public class EmployeeRepository: IEmployeeRepository
{
private static IList<Employee> employees;
static EmployeeRepository()
{
employees = new List<Employee>();
employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee1", "男", new DateTime(, , ), "销售部"));
employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee2", "男", new DateTime(, , ), "人事部"));
employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee3", "女", new DateTime(, , ), "财务部"));
}
public IEnumerable<Employee> GetEmployees(string id = "")
{
return employees.Where(e => e.Id == id || string.IsNullOrEmpty(id) || id == "*");
}
}

1.看看最新的DependencyResolver方式的实现,新建类 NinjectDependencyResolver 来实现IDependencyResolver的GetService和GetSerivices两个接口,

注意这里的Bind的方法,这里是为Controller注册Service的核心代码,所有Controller中以来的Ninject接口服务都在这里注册(接口与实现分离,Ninject托管)

public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel; public NinjectDependencyResolver()
{
kernel = new StandardKernel();
Bind();
} public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
Bind();
} public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
} public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
} private void Bind()
{
this.kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
}

上面已经注册了服务,现在需要把注册信息告诉Controller的Builder工厂;MVC5把这个工作已经自动化了,当最上面引入Ninject.Web.Common的时候,已经在App_Start文件夹下自动生成了NinjectWebCommon,注意RegisterServices方法需要我们主动将上面已经写好的注册类NinjectDependencyResolver初始化给Mvc.DependencyResolver对象,大家不难发现这里是对当前程序的全局设置,事实上NinjectWebCommon的Start方法比Global中Application_Start方法更早的执行,已便对整个应用程序做好初始化

public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper(); /// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
} /// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
} /// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); RegisterServices(kernel);
return kernel;
} /// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
}

到此Ninject已经引入完成了,怎么使用呢

下面添加一个对Employee操作的Controller, 声明一个IEmployeeRepository服务,注意这里是接口,在上面打上[Inject]标记后,在Action方法中就可以随意使用Employee服务了。可能有人疑惑这里的IEmployeeRepository没实例化如何就能使用,其实上面实现的RegisterServices方法中,已经对ControllerBuilder的初始化了注册信息,所有实现Controller的子类在实例化时根据[Inject]标记查找注册信息中的实现类进行初始化服务,在Action中引用的已经是实例化好的服务实体了

public class EmployeeController : Controller
{
[Inject]
public IEmployeeRepository Repository { get; set; } public ActionResult Index()
{
var employees = this.Repository.GetEmployees();
return View(employees);
} public ActionResult Detail(string id)
{
Employee employee = this.Repository.GetEmployees(id).FirstOrDefault();
if (null == employee)
{
throw new HttpException(, string.Format("ID为{0}的员工不存在", id));
}
return View(employee);
}
}

读到这算是知其然了,感觉很麻烦,为什么不直接在controller里new一个EmployeeRepository,接口都省了,想到这点说明你很勤于思考,回答这点需要说下为什么要引入Ninject,或者说IOC有什么好处,多做了那么多复杂的动作,好处呢

1. 这里托管给Jinject的服务实例会根据访问量最大限度的节约实例创建,如果省了这些,我们不得不在每个controller中保留要依赖的服务对象占用资源

2.controller中并没有直接对服务的实现类依赖,而是引用的接口,也就是说,controller开发者不需要关心服务是否已经现实,只在接口已经声明就可以开发,这即是实现当下最流行的敏捷开发的基础,后端服务的实现和前端的交互可同时进行(注意这里的接口集应该独立在新建的程序集中而不是放在MVC应用程序集,后面基于IOC框架设计再扩展)

3.MVC应用程序使用的所有服务都托管在Ninject而不是散落在controller(甚至到页面上), 对于安全策略,日志记录,错误处理可以集中处理,相当于对前端有了一个总阀

4.对于后端的扩展和模块化设计提供了便捷,这点比较宽泛

附言:

MVC5中的NinjectWebCommon类的CreateKernel方法中提供了IHttpModule的Bind,这里为喜欢玩管道的打开了一扇窗,让这版MVC成了一个新的过渡

2.Activitor激活实现

这里也是在ControllerBuilder初始化时做文章

public class NinjectControllerActivator : IControllerActivator
{
public IKernel Kernel { get; private set; }
public NinjectControllerActivator()
{
this.Kernel = new StandardKernel();
AddBindings();
}
public IController Create(RequestContext requestContext, Type controllerType)
{
return (IController)this.Kernel.TryGet(controllerType) as IController;
}
private void AddBindings()
{
this.Kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
}
}

对应在Global的Application_Start方法中是这样告诉Builder的,这里通过初始化CountrollerFactory对象实现服务注册信息的注入

NinjectControllerActivator controllerActivator = new NinjectControllerActivator();
DefaultControllerFactory controllerFactory = new DefaultControllerFactory(controllerActivator);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);

看到ControllerFactory可能有人会想起Unity的方式,后面将Ninject比对下Unity

参考文章:

http://www.cnblogs.com/artech/archive/2012/04/01/controller-activation-032.html

http://www.cnblogs.com/stoneniqiu/p/4594642.html

轻量级IoC框架Ninject.NET搭建的更多相关文章

  1. 轻量级IOC框架:Ninject

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

  2. IOC框架Ninject实践总结

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

  3. 轻量级IOC框架Guice

    java轻量级IOC框架Guice Guice是由Google大牛Bob lee开发的一款绝对轻量级的java IoC容器.其优势在于: 速度快,号称比spring快100倍. 无外部配置(如需要使用 ...

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

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

  5. java轻量级IOC框架Guice(转)

    出处:http://www.cnblogs.com/whitewolf/p/4185908.html Guice是由Google大牛Bob lee开发的一款绝对轻量级的java IoC容器.其优势在于 ...

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

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

  7. java轻量级IOC框架Guice

    Google-Guice入门介绍(较为清晰的说明了流程):http://blog.csdn.net/derekjiang/article/details/7231490 使用Guice,需要添加第三方 ...

  8. 轻量级IOC框架SwiftSuspenders

    该框架的1.6版本位于https://github.com/tschneidereit/SwiftSuspenders/blob/the-past/,现在已经出了重新架构的2.0版本,所以我决定先研究 ...

  9. 轻量级IOC容器:Ninject

    Ninject是一个快如闪电.超轻量级的基于.Net平台的依赖注入框架.它能够帮助你把应用程序分离成一个个松耦合.高内聚的模块,然后用一种灵活的方式组装起来.通过使用Ninject配套你的软件架构,那 ...

随机推荐

  1. Python re标准库

    re模块包含对正则表达式的支持. 一.什么是正则表达式 正则表达式是可以匹配文本片段的模式.最简单的正则表达是就是普通字符串,可以匹配其自身.你可以用这种匹配行为搜索文本中的模式,或者用计算后的值替换 ...

  2. js里json和eval()

    JSON * - JS中的对象只有JS自己认识,其他的语言都不认识 * - JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别, * 并且可以转换为任意语言中的对象,JSON在开发中主 ...

  3. Vim统计字符串出现次数

    关键命令: :%s/pattern//gn 参数说明: % - 指明操作区间,%表示全文本:可以使用1,$或者行区间代替 s – substitute,表示替换 pattern - 要查找的字符串 / ...

  4. PHP如何实现百万级数据导出

    公司目前有一个需求,需要对一个日增量在20万+数据量的数据表中的数据进行可自定义条件筛选的导出数据,该功能需要对多个部门进行开发使用,要保证功能可用的前提下,尽量优化体验. 首先介绍一下当前可利用的资 ...

  5. http://www.narkii.com/club/forum-46-1.html 纳金学习论坛,主要是讨论一些unty3D方面的事情,技术栈比较前沿,

    http://www.narkii.com/club/forum-46-1.html  纳金学习论坛,主要是讨论一些unty3D方面的事情,技术栈比较前沿,

  6. laravel请求处理管道例子

    例子: <?php interface Middleware{ public static function handle (Closure $next);} class VerifyCsrfT ...

  7. Django之13种必会查询

    1.常见的13中查询方式(必须记住) <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> g ...

  8. dedecms 调用英文标题和栏目描述

    调用英文标题: 参考文献 http://www.dedecms51.com/dedecmsjiaocheng/chengxukaifa/149476.html 增加 dede/templets/cat ...

  9. php断点续传之文件上传与文件下载

    下载: 原理: Http头的 Range.Content-Range()未启用单点登录GerenalRequest URL: http://www.demotest.com/php/fileDownl ...

  10. C开发系列-字符串

    C语言字符串 C语言字符串本质是使用字符数组来存储的. #include <stdio.h> int main() { "jake"; // "jake&qu ...