在MVC3项目中结合NInject组件实现依赖注入的设计

本文介绍了在MVC3项目中使用NInject组件实现依赖注入设计的过程,包括创建业务实体、数据访问接口、HomeController以及如何引入和配置NInject组件。通过演示步骤和代码示例,详细解释了如何实现灵活的数据源切换,以及通过自定义ControllerFactory和DependencyResolver来完成依赖注入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在MVC3项目中结合NInject组件实现依赖注入的设计

这是本次MVC3讲座中的一个话题,整理出来给大家参考参考

名词解释

依赖注入:英文是Dependency Injection。有时候也称为反转控制(Ioc)吧。不管名词怎么讲,它的大致意思是,让我们的应用程序所依赖的一些外部服务,可以根据需要动态注入,而不是预先在应用程序中明确地约束。这种思想,在当前的软件开发领域,为了保证架构的灵活性,应该还是很有意义的。

在MVC这个框架中,为依赖注入的设计提供了先天的支持。结合一些我们熟知的DI组件,例如NInject,我们可以较为容易地实现上述提到的功能。

 

场景介绍

我们的应用程序,需要支持各种不同的数据源,而且我们希望日后可以很容易地切换,不会因为数据源的变化而导致对Contoller或者Model,或者View做修改。

 

本文完整源代码,请通过这里下载 MvcApplicationDISample.rar

 

演练步骤

第一步:准备一个MVC项目(选择空白模板)

第二步:准备一个业务实体类型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcApplicationDISample.Models
{
    public class Employee
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

第三步:准备一个数据访问的接口定义

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using MvcApplicationDISample.Models;

namespace MvcApplicationDISample.Services
{
    public interface IDataService
    {
        Employee[] GetEmployee();
    }
}

第四步:创建一个HomeController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplicationDISample.Services;
using MvcApplicationDISample.Models;


namespace MvcApplicationDISample.Controllers
{
    public class HomeController : Controller
    {

        IDataService DataService;
        public HomeController(IDataService>//
        // GET: /Home/

        public ActionResult Index()
        {
            var data = DataService.GetEmployee();
            return View(data);
        }

    }
}

注意,这里需要为HomeController添加一个特殊的构造函数,传入IDataService这个接口。通常,所有的DI组件都是通过这样的方式注入的。

在设计HomeController的时候,我们不需要关心到底日后会用具体的哪种DataService,我们只是要求要传入一个IDataService的具体实现就可以了,这就是DI的本质了。

 

到这里为止,我们该做的准备工作基本就绪了。下面来看看如何结合DI组件来实现我们的需求

 

第五步:引入NInject组件

这是我比较喜欢的一个DI组件。它还针对MVC3专门有一个扩展

 

添加这个组件之后,除了自动添加了很多引用之外,还有一个特殊的文件App_Start\NinjectMVC3.cs

 

[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplicationDISample.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplicationDISample.App_Start.NinjectMVC3), "Stop")]

namespace MvcApplicationDISample.App_Start
{
    using System.Reflection;
    using Microsoft.Web.Infrastructure.DynamicModuleHelper;
    using Ninject;
    using Ninject.Web.Mvc;

    public static class NinjectMVC3 
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start() 
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
            DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
            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();
            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)
        {
        }        
    }
}

这个类型很有意思,WebActivator.PreApplicationStartMethod这个方法其实是注册了一个在MVC程序启动之前运行的方法。这些代码大家应该能看懂,它在CreateKernel中,添加一个新的Kernel(用来做注入的容器)。

 

第六步:创建一个IDataService的具体实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MvcApplicationDISample.Models;

namespace MvcApplicationDISample.Services
{
    public class SampleDataService:IDataService
    {
        #region IDataService Members

        public Employee[] GetEmployee()
        {
            return new[]{
                new Employee(){ID=1,FirstName="ares",LastName="chen"}};
        }

        #endregion
    }
}

作为举例,我们这里用了一个硬编码的方式实现了该服务。

第七步:实现注入

回到App_Start\NinjectMVC3.cs这个文件,修改RegisterServices方法如下

       /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<Services.IDataService>().To<Services.SampleDataService>();
        }      

第八步:测试Controller的功能

我们可以看到,数据已经展现出来了。这说明,HomeController中的Index方法,确实调用了我们后期插入的这个SampleDataService。而通过下图,则可以更加清楚看到这一点

到这里为止,我们就结合Ninject组件实现了一个简单的依赖注入的实例。Ninject 针对MVC 3有这么一个特殊的文件,可以极大地方便我们的编程。但即便没有这个文件,我们也可以通过另外一些方法来实现需求。

下面介绍两种比较传统的,通过扩展MVC组件实现的方式

第一种:实现自定义ControllerFactory

我们都知道,Controller其实都是由ControllerFactory来生成的,那么,为了给所有新创建从Controller都自动注入我们的服务,那么就可以从ControllerFactory这个地方动动脑筋了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ninject;
using MvcApplicationDISample.Services;

namespace MvcApplicationDISample.Extensions
{
    public class InjectControllerFactory:DefaultControllerFactory
    {

        private IKernel kernel;
        public InjectControllerFactory()
        {
            kernel = new StandardKernel();
            kernel.Bind<IDataService>().To<SampleDataService>();
        }
        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            return (IController)kernel.Get(controllerType);
        }
    }
}

要使用这个自定义的 ControllerFactory,我们需要修改Global.ascx文件中的Application_Start方法,添加下面的粗体部分代码

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

           ControllerBuilder.Current.SetControllerFactory(new Extensions.InjectControllerFactory());
        }

 

这样做好之后,我们可以测试HomeController中的Index这个Action,我们发现它还是能正常工作。

 

 

第二种:实现自定义的DependencyResolver

顾名思义,这就是MVC框架里面专门来处理所谓的依赖项的处理器。可以说这是MVC专门为DI准备的一个后门。下面是我写好的一个例子

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ninject;
using MvcApplicationDISample.Services;

namespace MvcApplicationDISample.Extensions
{
    public class InjectDependencyResolver:IDependencyResolver
    {
        private IKernel kernel;

        public InjectDependencyResolver()
        {
            kernel = new StandardKernel();
            kernel.Bind<IDataService>().To<SampleDataService>();
        }

        #region IDependencyResolver Members

        public object GetService(Type serviceType)
        {
            return kernel.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return kernel.GetAll(serviceType);
        }

        #endregion
    }
}
 

那么,如何使用这个自定义的处理器呢?

很简单,我们仍然是修改Global.asax文件中的Application_Start方法

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            //ControllerBuilder.Current.SetControllerFactory(new Extensions.InjectControllerFactory());

            DependencyResolver.SetResolver(new Extensions.InjectDependencyResolver());
        }



请注意,之前那个设置ControllerFactory的代码,我们可以注释掉了

这个解决方案的最终效果和之前是一样的。

一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值