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. Angular遇上CoffeeScript - NgComponent封装

    CoffeeScript是基于JavaScript的一门扩展小巧语言,它需要编译成JavaScript,然后再运行与浏览器或者Nodejs平台.JavaScript由于商业原因10天时间就匆忙诞生,所 ...

  2. [译]libev和libevent的设计差异

    本文译自what's the difference between libev and libevent? 作者是libev作者 [问]两个库都是为异步io调度而设计,在Linux上都是使用epoll ...

  3. SpringMVC执行流程

    Spring mvc是一个机遇DispacterServlet的MVC框架,每一个请求都是通过DispacterServlet派发的,具体流程如下: 1.web容器加载后,用户向服务器发送请求,前端控 ...

  4. java compiler level does not match the version of the installed java project facet 解决方案

    项目出现 java compiler level does not match the version of the installed java project facet 错误,一般是项目移植出现 ...

  5. Discuz门户首页关键词和描述显示“首页”的解决方法

    Discuz社区在后台设置好门户标题.关键字.描述,更新缓存,发现用户登录状态下,门户首页的关键字和描述正常显示:但在游客状态下不显示,在某工具中查看到的情况如下: 现找到两种解决办法:(记得修改前备 ...

  6. 收集的React.JS资料

    主页 http://facebook.github.io/react/ https://github.com/facebook/react   中文站 http://www.reactjs.cn/ h ...

  7. OpenNURBS 3DM Viewer

    OpenNURBS 3DM Viewer eryar@163.com Abstract. The openNURBS Toolkit consists of C++ source code for a ...

  8. Ruby之入门(一)

    前言 这门语言很少去听过,可能是没怎么用到就不会听到太多关于ruby的消息,工作需要这门语言,需要从0开始学习这门语言,慢慢学习简直...太神奇了...,原谅我见识浅薄.原来很早就已经出世了,园子中也 ...

  9. 【iOS】NSNumberFormatter

    介绍 NSNumberFormatter 应该可以满足你对数据形式的一般需求,值得了解一下. NSNumber *num1 = [NSNumber numberWithDouble:1234567.8 ...

  10. js实现css3的过渡,需要注意的一点(浏览器优化)

    大部分浏览器对元素几何改变时候的重排做了优化.据说是这样子,一定时间内本应多次重排的改变,浏览器会hold住,仅一次重排.其中如果使用分离的一步处理过程,例如计时器,依然多次重排.例如,当我们应用tr ...