热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【转】007.ASP.NETMVC控制器依赖注入

原文链接:http:www.codeproject.comArticles560798ASP-NET-MVC-Controller-Dependency-Injection-for-Be

原文链接:http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be

前言:在这篇文章中,我将通过一个demo,直截了当地说明依赖注入在MVC框架中的使用。

内容列表:

  1.介绍

  2.为什么使用控制器依赖注入

  3.控制器静态结构

  4.自定义控制器

  5.Framework中控制器的创建

  6.为什么使用控制器工厂模式

  7.控制器工厂模式

    7.1.目标1

    7.2.目标2

  8.使用MEF实现控制器工厂模式

  9.重点补充

一:介绍

  

  首先简单地说明控制器在MVC框架中要做的几件事情

  1.接收HTTP请求

  2.处理HTTP请求

  3.操作客户端输入的数据

  4.发送回复给客户端

  5.作为Model和View的中转站

  MVC框架在运行时自己创建控制器对象,有一个先决条件,控制器类的构造函数是无参的。如果你想传递一个对象作为控制器的参数,这种情况我们又该如何处理?创建这种类型的控制器会失败,我们需要创建自己的控制器,将控制器参数注入到控制器。

  有多种方式可以将参数注入到控制器的构造方法中

  1.设置属性

  2.通过方法

  3.构造方法

  在这篇文章中,我将解释如何使用控制器注入到MVC中的构造函数中。如果不使用自定义控制器工厂模式,控制器注入是无法实现的。当然我也会解释如何创建简单的控制器工厂,然后注册到MVC框架。我也会展示一种方法注入控制器,使用MEF。

二.为什么使用控制器注入

  在现实的程序开发中,你会看到绝大多数的MVC程序需要注入它所依赖的组件。你可以直接创建组件在控制器中,而不需要注入它们。在这种情况下,组件和控制器紧密结合,如果一个组件的扩展发生了改变,或者一个新版本的组件要使用,你就需要改变控制器中的实现(PS:讲解为什么使用控制器注入)

  当你想使用单元测试的时候,另一种困难你可能会遇到。你不能测试这些控制器在一个独立的单元。你不能模仿一些新的特性,如果不能模仿,你将不能成功运行你的代码在一个独立的环境。

三.控制器静态结构

  MVC框架中的控制器结构是定义在一个叫Controller的抽象类中,如果你想创建一些控制器,首先你需要创建一个类,从抽象类Controller中继承,UML类图如下:

1

  所有的控制器都有一个根接口IController,抽象类ControllerBase从它去实现自己的方法。另一个抽象类从ControllerBase中继承,这个类就是Controller,所有的自定义的控制器类都要从Controller中继承,或者从它的子类中继承。

四.简单的自定义控制器

  如果你创建一个MVC工程,你将会得到两个控制器,AccountController和HomeController

2

  如果你去看HomeController中的代码实现,你会发现它没有自己的构造方法。

 1 public class HomeController : Controller  2 {  3     public ActionResult Index()  4  {  5         ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";  6         return View();  7  }  8     public ActionResult About()  9  { 10         ViewBag.Message = "Your app description page."; 11         return View(); 12  } 13 } 

我们都知道这里没有一个构造方法,但在编译时会创建一个无参的构造方法。

1 ublic class HomeController : Controller 2 { 3     public HomeController() 4  { 5  } 6 } 

现在我将要创建一个ILogger接口及它的一个实现类DefaultLogger类,Home控制器会使用ILogger类型的对象作为参数,注入到它的控制器构造方法中。

 1 public interface ILogger  2 {  3     void Log(string logData);  4 }  5 public class DefaultLogger : ILogger  6 {  7     public void Log(string logData)  8  {  9         System.Diagnostics.Debug.WriteLine(logData, "default"); 10  } 11 } 

带参ILogger的Home控制器构造方法如下:

1 public class HomeController : Controller 2 { 3     private readonly ILogger _logger; 4     public HomeController(ILogger logger) 5  { 6         _logger = logger; 7  } 8 } 

直到现在你也没找到我们在什么地方实例化了DefaultLogger对象,也不知道如何传递这个对象到控制器的构造方法中,在编写代码阶段程序不会报错,但是在运行代码会报错,如下:

4

看上面的线程记录,DefaultControllerActivator对象会抛出一个异常MissingMethonException。如果你到MSDN,找这个异常是如何引发的,你会发现找到不到适当的方法。看接下来的异常InvalidOperationException,它确实包含了MissingMethodException,将下来你会看到更加有用的信息,确保在控制器构造方法中有一个带参数的构造方法。如果想让代码工作正常,我必需要加带一个参数的构造方法,框架会创建控制器对象通过我们创建的那个构造方法。问题在于,我们如何传递一个一个DefaultLogger对象到这个控制器。请继续你好练习,我们接着往下看。

五.MVC框架是如何创建控制器对象

  在我们开始注入DefaultLogger对象到HomeController之前,我们要有一个概念,MVC框架是如何创建一个控制器对象的。IControllerFactory接口的主要责任就是创建控制器对象。DefaultControllerFactory是框架默认提供的可扩展的类。如果你添加一个无参的构造方法,然后设置一个断点,你将会发现程序在这一刻,将停留在这里。

看上面的图片,你可以看到IControllerFactory类型的一个DefaultControllerFactory对象,DefaultControllerFactory有一些方法,如:Create,GetControllerInstance,CreateController,这些方法将会创建一个HomeController对象,MVC框架是开源的,如果你想知道更多的方法,可以下载官方的资源,自己去阅读。你看调试的代码,你可以看到DefaultControllerFactory对象被CurrentControllerFactory

六.为什么要自定义控制器工厂

 现在我们知道默认的控制器工厂使用一个无参的构造方法创建一个控制器对象。我们可以注入自己的带参的控制器构造方法。

 1 public class HomeController : Controller  2 {  3     private readonly ILogger _logger;  4     public HomeController():this(new DefaultLogger())  5  {  6  }  7     public HomeController(ILogger logger)  8  {  9         _logger = logger; 10  } 11 }    

我发现许多的开发者都对上面依赖注入有所误解,它不是一个依赖注入的形式。这个确实违反了组件的原则。而这个原则的愿意是:上层的模块不能依赖于低层级的模块,双方都要依赖于抽象层,细节要在体现在抽象层。在上面的代码中,HomeController创建了自己的DefaultLogger对象。它直接依赖于ILogger接口的扩展(DefaultLogger),如果在将来一个新的扩展(扩展了ILogger接口),我们需要修改我们HomeController中的方法,所以我们需要使用适当的方法去注入我们的组件。我们要使用一个带参的构造方法去注入我们的ILogger 组件,但是默认的 DefaultControllerFactory不支持我们这么做,所以我们要创建自己的控制器工厂。

七.自定义控制器工厂

  我使用两种方法展示如何创建自己的控制器工厂。

  7.1途径1

  我们可以创建一个新的控制器工厂,扩展了IControllerFactory接口,假定我们自定义的控制器工厂的名称叫CustomControllerFactory,如下

 1 public class CustomControllerFactory : IControllerFactory  2 {  3     public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)  4  {  5         ILogger logger = new DefaultLogger();  6         var cOntroller= new HomeController(logger);  7         return controller;  8  }  9     public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior( 10        System.Web.Routing.RequestContext requestContext, string controllerName) 11  { 12         return SessionStateBehavior.Default; 13  } 14     public void ReleaseController(IController controller) 15  { 16         IDisposable disposable = controller as IDisposable; 17         if (disposable != null) 18  disposable.Dispose(); 19  } 20 } 

现在第一步,我们需要将CustomControllerFactory注册到MVC框架,完成这件事要在Application_Start事件中书写代码。

 1 public class MvcApplication : System.Web.HttpApplication  2 {  3     protected void Application_Start()  4  {  5  RegisterCustomControllerFactory ();  6  }  7 }  8 private void RegisterCustomControllerFactory ()  9 { 10     IControllerFactory factory = new CustomControllerFactory(); 11  ControllerBuilder.Current.SetControllerFactory(factory); 12 } 

如果你运行你的程序,你会发现那个无参的构造方法没有被执行,那个带参的构造方法执行了。你的问题就这么简单的解决了。

你可以构建你的控制器工厂使用反射机制。

 1 public class CustomControllerFactory : IControllerFactory  2 {  3     private readonly string _controllerNamespace;  4     public CustomControllerFactory(string controllerNamespace)  5  {  6         _cOntrollerNamespace= controllerNamespace;  7  }  8     public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)  9  { 10         ILogger logger = new DefaultLogger(); 11         Type cOntrollerType= Type.GetType(string.Concat(_controllerNamespace, ".", controllerName, "Controller")); 12         IController cOntroller= Activator.CreateInstance(controllerType, new[] { logger }) as Controller; 13         return controller; 14  } 15 } 

  7.2途径2

  这里方法不是去扩展IControllerFactory接口,而是去继承DefaultControllerFactory类,通过修改其中的方法。当然也要将控制器工厂注入到程序启动的事件中。代码如下:

1 public class CustomControllerFactory : DefaultControllerFactory 2 { 3     protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) 4  { 5         ILogger logger = new DefaultLogger(); 6         IController cOntroller= Activator.CreateInstance(controllerType, new[] { logger }) as Controller; 7         return controller; 8  } 9 } 

(去掉了MEF创建自定义控制器工厂的方法,因为自己也实在不能理解,但是要看啊)。


推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • C# WPF自定义按钮的方法
    本文介绍了在C# WPF中实现自定义按钮的方法,包括使用图片作为按钮背景、自定义鼠标进入效果、自定义按压效果和自定义禁用效果。通过创建CustomButton.cs类和ButtonStyles.xaml资源文件,设计按钮的Style并添加所需的依赖属性,可以实现自定义按钮的效果。示例代码在ButtonStyles.xaml中给出。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
author-avatar
sdfqwerwfds
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有