IOC Of Ninject Base On ASP.NET MVC

说在之前的话

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(1987, 8, 24), "销售部"));
            employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee2", "男", new DateTime(1991, 7, 10), "人事部"));
            employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee3", "女", new DateTime(1993, 9, 21), "财务部"));
        }
        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(404, 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

时间: 2024-10-26 13:42:54

IOC Of Ninject Base On ASP.NET MVC的相关文章

IOC 容器在 ASP.NET MVC 中的应用

IOC:Inversion Of Control 翻译为控制反转,我们在面向对象软件开发过程中,一个应用程序它的底层结构可能由N种不同的构件来相互协作来完成我们定义的系统的业务逻辑.哪么每一个构件可能相互独立和相互依赖,如果相互依赖的构件中的某一个构件出现异常,就会影响到整个系统的稳定运行,对象之间的耦合关系是无法避免的,也是必要的,因为这是协同工作的基础.如何降低系统之间.模块之间和对象之间的耦合度,是软件工程永远追求的目标之一.为了解决对象之间的耦合度过高的问题,IOC 的理念被提出,并被成

ASP.NET MVC

[ASP.NET MVC 大牛之路]03 - C#高级知识点概要(2) - 线程和并发 摘要: 我也想过跳过C#高级知识点概要直接讲MVC,但经过前思后想,还是觉得有必要讲的.我希望通过自己的经验给大家一些指引,带着大家一起走上ASP.NET MVC大牛之路,少走弯路.同时也希望能和大家一起交流,这样也能发现我自己的不足,对我自己的帮助也是非常大的.建议大家对C#撑握的不错的时候,可以去看一些...阅读全文 posted @ 2014-12-29 23:15 Liam Wang 阅读(9730)

ASP.NET MVC Boilerplate简介

ASP.NET MVC Boilerplate简介 ASP.NET MVC Boilerplate是专业的ASP.NET MVC模版用来创建安全.快速.强壮和适应性强的Web应用或站点.它在微软默认MVC模版之上提供了要求最少的代码实现. 使用此模版的主要好处: 安全 性能 搜索引擎优化 (SEO) 可访问性 浏览器兼容 弹性和错误处理 简单调试和性能测试工具 设计模式和最佳实践 搜索 ASP.NET MVC Boilerplate 技术路线图 为什么需要ASP.NET MVC Boilerpl

ASP.NET MVC IOC 之Ninject攻略

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

ASP.NET MVC学前篇之Ninject的初步了解

1.介绍 废话几句,Ninject是一种轻量级的.基础.NET的一个开源IoC框架,在对于MVC框架的学习中会用到IoC框架的,因为这种IoC开源框架有很多,本篇的主题只有一个,就是让阅读过本篇幅的朋友逗知道IoC框架在项目中的作用,以及它的重要性. 这样做的目的是以便在以后的学习工作中选择自己中意的一个IoC框架来学习.使用,或者是自己去实现一个.好了,不废话了. 2.环境准备 1.新建个4.0Framework的一个控制台应用程序项目,名称为IoCDemo 2.在http://www.nin

[ASP.NET MVC 小牛之路]05 - 使用 Ninject实现依赖注入

在[ASP.NET MVC 小牛之路]系列上一篇文章(依赖注入(DI)和Ninject)的末尾提到了在ASP.NET MVC中使用Ninject要做的两件事情,续这篇文章之后,本文将用一个实际的示例来演示Ninject在ASP.NET MVC中的应用. 为了更好的理解和撑握本文内容,强烈建议初学者阅读本文前先阅读依赖注入(DI)和Ninject. 本文目录: 准备工作 新建一个名为BookShop的空白解决方案.在该解决方案中分别添加一个名为BookShop.WebUI的MVC空应用程序,和一个

Ninject之旅之十三:Ninject在ASP.NET MVC程序上的应用

摘要: 在Windows客户端程序(WPF和Windows Forms)中使用Ninject和在控制台应用程序中使用Ninject没什么不同.在这些应用程序里我们不需要某些配置用来安装Ninject,因为在Windows客户端应用程序里,开发者可以控制UI组件的实例化(Forms或Windows),可以很容易地委托这种控制到Ninject.然而在Web应用程序里,就不同了,因为框架负责了实例化UI元素.因此,我们需要知道怎样告诉框架委托这种控制责任给Ninject.幸运的是,让ASP.NET M

Ioc容器Autofac系列(2)-- asp.net mvc中整合autofac(转)

经过上篇蜻蜓点水的介绍后,本篇通过实例快速上手autofac,展示当asp.net mvc引入了autofac之后会带来什么. 创建Asp.net MVC并引入Autofac 首先,创建一个MVC站点,为方便起见,选初始带HomeController和AccountController的那种.然后通过NuGet或到Autofac官网下载来引入类库.个人推荐前者,因为从VS2010开始,已内集可视化的NuGet功能,使用起来非常方便.如下图所示: 这是vs2012的界面,点击"Manage NuG

在 ASP.NET MVC 应用中使用 NInject 注入 ASMX 类型的 Web Service

这几天,有同学问到为什么在 ASP.NET MVC 应用中,无法在 .ASMX 中使用 NInject 进行注入. 现象 比如,我们定义了一个接口,然后定义了一个实现. public interface IMessageProvider { string GetMessage(); } 定义一个接口的实现. public class NinjectMessageProvider : IMessageProvider { public string GetMessage() { return "T