博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MVC中的扩展点(四)控制器工厂
阅读量:6003 次
发布时间:2019-06-20

本文共 3725 字,大约阅读时间需要 12 分钟。

MVC中的扩展点(四)控制器工厂  

2012-07-29 23:54:32|  分类: |字号 

 
 
当路由系统找到与当前请求匹配的路由信息(RouteData),而路由信息中的RouteHandler为MvcRouteHandler,那么此请求将由MvcRouteHandler返回的MvcHandler来负责处理。默认情况下MvcHandler将根据请求上下文(RequestContext)中的信息找到对应的控制器和活动方法,通过调用活动方法,返回应答内容,将其返回给客户端。

    MvcHandler类通过使用单例类ControllerBuilder的GetControllerFactory方法获取当前指定的IControllerFactory对象,通过此对象来生成具体的IController控制器。对于MvcHandler来说,它只关心IController对象,即只负责调用IController的Execute方法来产生应答内容。Action方法是MVC框架默认Controller类中实现的一种机制,它通过路由信息中的action参数来确定调用Controller类中的某个对应方法,以此产生应答内容。

    默认情况下,MVC框架使用DefaultControllerFactory控制器工厂,它使用路由信息中的controller参数来确定具体的控制器类,并通过反射机制生成控制器实例。

    从MvcRouteHandler接收到请求到最终确定使用那个控制器,涉及到的类,如下图所示:

    通过ControllerBuilder的SetControllerFactory方法我们可以指定自定义的控制器工厂,自定义工厂可以直接实现IControllerFactory接口,也可以从DefaultControllerFactory类继承,如果直接实现IControllerFactory,则我们必须自己实现一种机制将路由信息与控制器对应起来。所以为了使用MVC中默认的路由解析功能,我们通常从DefaultControllerFactory继承,然后根据实际情况覆写GetControllerInstance与GetControllerType方法,其中GetControllerInstance用于返回一个IController控制器,GetControllerType用于根据路由信息获取合适的控制器类型。显然,在默认控制器工厂中,CreateController方法先调用GetControllerType找出类型,然后调用GetControllerInstance方法创建一个控制器实例。

    DefaultControllerFactory使用Activator.CreateInstance方法来创建控制器对象,所以MVC默认的控制器必须具有无参构造函数。下面我们使用依赖注入(DI)技术使我们的自定义控制器工厂具有实例化有参控制器。

    设想以下情景:领域模型中有个Product类,我们为其定义了一个IProductsRepository的存储管理类。首先,我们实现了一个SqlProductsRepository类,用于从SqlServer数据库中获取产品资料,然后,为方便测试,我们还实现了一个MockProductsRepository类,用于返回一个简单的产品列表。我们建立一个ProductsController控制器,为确定使用哪种存储实现,我们要求在生成控制器实例时,必须传入一个IProductsRepository对象:

    我们选用NInject开源库来实现DI(下载地址:):

1、下载NInject,并解压

2、新建一个空的MVC工程

3、添加引用Ninject.dll、System.Data.Linq

4、在SQL Server Management Studio Express中附加上源代码中的Test数据库

5、按上述类图实现各个接口及类

6、创建一个ProductsController,增加一个带IProductsRepository参数的构造函数

显示行号 复制代码  ProductsController
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Mvc;
  6.  
  7. namespace CnBlogs.ControllerFactory.Controllers
  8. {
  9. public class ProductsController : Controller
  10. {
  11. private IProductsRepository _repository;
  12.  
  13. public ProductsController(IProductsRepository repository)
  14. {
  15. _repository = repository;
  16. }
  17.  
  18. public ActionResult Index()
  19. {
  20. return View(_repository.GetProductsList());
  21. }
  22.  
  23. }
  24. }
  25.  
  26.  

7、创建与Index Action方法对应的视图Index.aspx

8、创建一个控制器工厂: NinjectControllerFactory

显示行号 复制代码  NinjectControllerFactory
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Mvc;
  6. using Ninject.Modules;
  7. using Ninject;
  8. using CnBlogs.ControllerFactory.Models;
  9. using System.Configuration;
  10.  
  11. namespace CnBlogs.ControllerFactory.Infrastructure
  12. {
  13. public class NinjectControllerFactory : DefaultControllerFactory
  14. {
  15. private IKernel _kernel = new StandardKernel(new MyModule());
  16.  
  17. protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
  18. {
  19. if (controllerType == null)
  20. return null;
  21. return (IController)_kernel.Get(controllerType);
  22. }
  23.  
  24.  
  25. private class MyModule : NinjectModule
  26. {
  27. public override void Load()
  28. {
  29. //Bind
    ()
  30. //    .To
    ();
  31.  
  32. Bind
    ()
  33. .To
    ()
  34. .WithConstructorArgument("connectstring", ConfigurationManager.ConnectionStrings["TestDb"].ConnectionString);
  35. }
  36. }
  37. }
  38. }
  39.  

9、在Global.asax.cs中设置自定义工厂

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
 
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}
 

 

    Ok,要在虚拟产品列表与真实的SqlServer中的产品列表中切换,我们只需修改MyModule中的Load方法,将Controller构造函数中的特定参数绑定到一个具体的实现。

    注意:本文涉及到有关的Linq、DI方面的知识,请参考相关资料。要运行本文示例,请先将源代码中的mdf文件附加到SqlServer Express中,并修改App.config中TestDb连接字符串的定义。

转载于:https://www.cnblogs.com/ppcompany/articles/2917124.html

你可能感兴趣的文章
Kafka High Level Consumer 会丢失消息
查看>>
时间轴
查看>>
入坑vim之配置文件vimrc
查看>>
java 获取系统当前时间的方法
查看>>
css关于鼠标样式的设置
查看>>
Ubuntu 10.04升级git 到1.7.2或更高的可行方法
查看>>
MyBATIS(即iBATIS)问题集
查看>>
Linux下autoconf和automake使用
查看>>
UDP之socket编程
查看>>
Spring Security4实战与原理分析视频课程( 扩展+自定义)
查看>>
Centos6.5升级系统自带gcc4.4.7到gcc4.8.0
查看>>
redis安装与配置文件详解
查看>>
VMware安装失败 “Failed to create the requested registry key Key:installer Error:1021"
查看>>
虚拟化系列-VMware vSphere 5.1 VDP备份管理
查看>>
接口设计
查看>>
同步工具类 java.util.concurrent.CountDownLatch
查看>>
带动量因子的BP网络源码(C#实现)
查看>>
Skia深入分析9——延迟渲染和显示列表
查看>>
mmap函数实现共享内存
查看>>
java笔记
查看>>