MVC框架之所以如此受欢迎的原因之一就是它十分注意支持关注分离,使各个功能部件尽量能够相互独立。今天我们就来看看MVC4如何使用DI方法实现一些组件的独立,使本来结合紧密的部件,松耦合。我现在所说的对于.net的一些初学者来说可能有点拗口,其实我也是一个实打实的初学者,自己开始看这段话的时候迟迟不能理解,但是当看了实例之后,消化了一下就还算是懂得了其中的一些韵味了。下面就让我来和大家分享一下我自己所理解的依赖性注入。希望大家能多指教。

那么接下来我们来看一个简单的例子,用Demo说话


我们新建一个MVC4的项目吧

然后选择Basic模板

点击Ok创建好项目

接着在Models文件夹添加一个IEmailSender接口,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DIShow.Models
{
public interface IEmailSender
{
public string SendEmail();
}
}

接着再添加一个EmailSender类实现IEmailSender接口,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace DIShow.Models
{
public class EmailSender:IEmailSender
{
public string SendEmail()
{
return "My Name is SendEmail,My Type is EmailSender";
}
}
}

现在我们在Controller文件夹里添加一个HomeController

我们要实现的功能就是在Controller里调用SendEmail方法来发送一个邮件。

我们在controller里添加如下代码就可以了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DIShow.Models; namespace DIShow.Controllers
{
public class HomeController : Controller
{
private IEmailSender emailSender;
public string Index()
{
emailSender = new EmailSender();
return emailSender.SendEmail();
} }
}

这个时候我们运行程序,就可以看到浏览器里的输出

现在我们唯一可以确定的就是这个程序时正确的。


那么现在我们就来谈谈这样简单的一个程序可以怎样做,来让他更为合理,具有清晰的结构。

首先我们可以看到,我们有一个接口和一个实现这个接口的类,肯定有同学会想问,就这样的程序干嘛还要多此一举搞个接口,直接在controller里面实例化这个类,再调用SendEmail方法就好了。我想说的是,接口只是为了后面的改进做一个铺垫,现在看来确实是可有可无。

然后现在我提出一个问题,要是我有多个发送邮件的程序,也就是说有多个类似于EmailSender这样的类。要是我想换一个发送程序,岂不是我每次必须要修改控制器中的代码,以此来切换发送程序。这样的做法对于很小的程序来说还好,对于稍微大一点的程序就会变得很不合理。这样就把控制器的代码变得十分繁琐了。而且对于MVC程序来说控制器就相当于大脑,你不能总是修改大脑,最合理的方式就是修改提供程序,然后大脑只需要一个调用执行该方法的接口就行了,并不需要关心具体是怎么实现的。回到我们现在的例子,我们要实现的效果就是在controller里面不出现EmailSender,只需要一个IEmailSender接口。我们只需要实例化这个接口的具体实现就行了。所以我们可以对控制器中的代码进行如下改进

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DIShow.Models; namespace DIShow.Controllers
{
public class HomeController : Controller
{
private IEmailSender emailSender;
public HomeController(IEmailSender emailSender)
{
this.emailSender = emailSender;
}
public string Index()
{
return emailSender.SendEmail();
} }
}

我们可以看到这时我们就实现了HomeController和EmailSender之间毫无联系,当然这样的程序时没办法运行的,因为程序并不知道如何实例化IEmailsender这个接口,虽然有一个实现了这个接口的类,但是我们并没有告诉程序应该用哪个类去实例化这个接口。所以接下来我们就要去告诉程序应该用哪个类去实例化这个接口。


解决问题的方法就是“DI容器”,这个容器就是在接口(例如IEmailSender)和实现接口的具体类(例如EmailSender)之间担任一个中间人,由他来处理具体通过实例化哪个类来实例化接口。

而DI容器应该如何实现呢,两种方法,第一种就是自己创建一个DI容器,第二种就是用网上的开源代码,本人用的是Ninject包,网址:http://www.ninject.org

而在本篇博客中,由于作者本人能力有限,所以将只演示第二种方法。
大家可以在我提供的网址上看一下该包的具体细节然后下载包来进行使用,也可以直接在VS中的引用中进行安装。如下图

安装好后接下来我们就开始用使用这个包来帮助我们创建DI容器


第一步:创建一个依赖性链解析器

这个解析器就是类似搞出一个中介,让程序知道哪一个类去实例化哪一个接口。我们可以在mvc项目中,新建一个文件夹,例如Infrastructure,然后在里面建一个类:NinjectDependencyResolver 并实现IDependencyResolver接口,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Ninject;
using System.Web.Mvc;
using DIShow.Models; namespace DIShow.Infrastructure
{
public class NinjectDependenceyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependenceyResolver()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)//IDependencyResolver的方法
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)//IDependencyResolver的方法
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<IEmailSender>().To<EmailSender>();
}
}
}

第二步:注册依赖解析器

通过注册依赖解析器来告诉MVC框架,用户希望使用自己的依赖解析器,那么在哪里注册呢,当然是在管理整个程序运行的地方注册-Global.asax.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using DIShow.Infrastructure; namespace DIShow
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); DependencyResolver.SetResolver(new NinjectDependenceyResolver());
}
}
}

DependencyResolver.SetResolver(new NinjectDependenceyResolver())便实现了注册

通过以上两步DI容器的创建和注册就已经搞定了。


现在我们的这个小项目的依赖性注入就完全搞定了,我们来运行程序检测一下正确与否

事实说明是正确的。


最后我们还是来简单总结一下吧。

首先我们来梳理一下程序的运行过程:程序启动,根据路由系统我们到了HomeController,然后运行到HomeController构造函数的时候发现需要传入一个IEmailSender的实例化对象。这个时候程序回到Global当中,发现Global确实注册这样一件事,就是我们指定了怎样去实例化接口。通过我们的注册信息,我们找到了我们的DI容器,也就是NinjectDependenceyResolver类。然后我们在这个类里面传入一个类型给GetService,然后它通过查看我们的绑定信息,这个中介就发现我们是把IEmailSender绑定到EmailSender上面去的。于是就 实例化了EmailSender得到了一个对象,最后返回给了在HomeController中的构造函数中的参数sendEmail。于是后面就可以成功执行方法了。

然后我们来看一下实现这些过程主要做了那几步:

1.写出接口和实现类。

2.在控制器中只调用接口方法,不出现具体类

3.创建一个DI容器,将接口和具体类绑定

4.在Global中注册这个容器

就这样四步就搞定了。以后要是想要切换另一个发送程序,只需要在DI容器中将接口绑定到另一个实际类上就可以了,控制器不需要做任何修改。

好啦,我的分享就到此为止了,以后要是学到了更多有意思的东西还会和大家继续分享的。

MVC依赖性注入概述的更多相关文章

  1. .NET 用 Unity 依赖注入——概述注册和解析类型(1)

    本文内容 Unity 概述 环境 一个真实的例子 类型注册(Type Registrations) 解析类型(Resolving Types) 跳槽,新公司使用了 Unity,初步看了一下,公司的使用 ...

  2. 解决Autofac MVC 自动注入在 Areas拆分到不同dll下的注入失败问题

    由于项目业务复杂,创建了多个Areas 并把他们放在了不同的项目中,项目使用AutoFac做的IOC 配置代码为 public class MvcApplication : System.Web.Ht ...

  3. Asp.Net MVC 之 Autofac 初步使用2 集成mvc 属性注入以及自动注入

    首先看下Demo2的结构     然后下面一步步将Autofac集成到mvc中. 首先,定义Model Product.cs public class Product { public int Id ...

  4. 基础教程:视图中的ASP.NET Core 2.0 MVC依赖注入

    问题 如何在ASP.NET Core MVC Views中注入和使用服务. 解 更新 启动 类来为MVC添加服务和中间件. 添加一项服务 添加一个Controller,返回 ViewResult. 添 ...

  5. MVC架构模式概述

    MVC MVC概述: Model–view–controller (MVC) is a software architectural pattern for implementing user int ...

  6. MVC 依赖注入

    本人主要是写给我自己看的,文章没有过多的解释,只留下步骤. 目的:面向接口编程,做到低耦合,高内聚 1.利用Nuget 管理工具,安装Ninject. 2.随便新建一个接口和一个实现类,我在此项目中是 ...

  7. MVC 依赖注入扩展

    需求: 小明想要完成一个功能F,需要一把锤子T. 有两种办法可以实现: 1)小明很爱动手,精力很旺盛,于是,自己创建一个具有功能F的锤子T,并使用T来完成F: 2)小明很懒,天天睡大觉,于是,他叫小健 ...

  8. spring mvc处理流程概述

    大部分Java应用都是Web应用,展现层是Web应用不可忽略的重要环节.Spring为展现层提供了一个优秀的Web框架-Spring MVC.和众多其他Web框架一样,它基于MVC设计理念,此外,它采 ...

  9. 1..net mvc的原理概述

    请求过来,根据ip和端口,由iis服务器进行接收,如果是静态文件则直接返回文件内容,如果无法解析,则根据映射规则找到对应请求后缀 的ASPNET_ISAPI.dll处理程序集,交由其进行处理. 1.此 ...

随机推荐

  1. 走向面试之数据库基础:二、SQL进阶之case、子查询、分页、join与视图

    一.CASE的两种用法 1.1 等值判断->相当于switch case (1)具体用法模板: CASE expression WHEN value1 THEN returnvalue1 WHE ...

  2. Android学习第一天-adb常用命令

    平时开发android应用 的时候,我们都会用到包含在Android SDK中一系列的工具,或许我们通过Eclipse去调用,又或许,我们自己通过打开终端进行手动输入并且执行,下面我们来一起学习下这些 ...

  3. 七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL

    本节又带了一些常用的,却很难理解的问题,本节从文件上传功能的实现引出了线程使用,介绍了线程饥饿的解决方法,异常处理方法,了解RouteTable自定义路径 . 系列文章 七天学会ASP.NET MVC ...

  4. Step by step SQL Server 2012的安装

    原创地址:http://www.cnblogs.com/jfzhu/p/4006744.html 转载请注明出处 计算机要先设置固定ip,加入域,然后安装账号需要有本地管理员的权限. 演示环境的操作系 ...

  5. CentOS RDO方式快速安装OpenStack

    一.了解RDO RDO是什么? RDO是红帽Red Hat Enterprise Linux OpenStack Platform的社区版,类似RHEL和Fedora,RHEV和oVirt这样的关系. ...

  6. [转]Linux常用命令

    系统信息arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS / ...

  7. MongoDB 搭建副本集

    副本集(Replica Set)是一组MongoDB实例组成的集群,由一个主(Primary)服务器和多个备份(Secondary)服务器构成.通过Replication,将数据的更新由Primary ...

  8. 鼠标mouse事件冒泡处理

    简单的鼠标移动事件: 进入 mouseenter:不冒泡 mouseover: 冒泡 不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件 只有在鼠标指针穿过被选元素时,才会触发 m ...

  9. 【转】如何让你的Android SDK下载或者升级快如闪电

    准备学习Android开发,但是Android SDK Manager界面都刷不出来,今天看到了一篇文章,顿时就解决了,原文地址http://qichaochen.github.io/2014/12/ ...

  10. MVC4做网站Demo进行重写的问题。

    自从学习MVC4开始,边学边写这个demo,写了也有一年多了.开始觉得是一个小例子把所有的代码都写在一个项目中,边写边改越写越混乱,越到后来很多东西自己都理不清了.后来在群里跟 @怒放 在讨论这个问题 ...