学习ASP.NET MVC5框架揭秘笔记-ASP.NET MVC是如何运行的(三)

Controller的激活

ASP.NET MVC的路由系统通过注册的路由表对当前HTTP请求实施路由解析,从而得到一个用于封装路由数据的RouteData对象,这个过程是通过自定义的UrlRoutingModuleHttpApplicationPostResolveRequestCache事件进行注册实现的。由于得到的RouteData对象中已经包含了目标Controller的名称,我们需要根据该名称激活对应的Controller对象。

1.MvcRouteHandler

通过前面的介绍我们知道,继承自RouteBaseRoute类型具有一个类型为IRouteHandler借口的属性RouteHandler,它主要的用途就是用于根据指定的请求上下文(RequestContext)来获取一个HttpHandler对象。当GetRouteData方法被执行后,RouteRouteHandler属性值将反映在得到的RouteData的同名属性上,在默认的情况下,RouteRouteHandler属性是一个MvcRouteHandler对象。

对于我们的“迷你版”ASP.NET MVC框架来说,MvcRouteHandler是一个具有如下定义的类型。在实现的GetHttpHandler方法中它会直接返回一个MvcHandler对象。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MvcRouteHandler : IRouteHandler  
  2.     {  
  3.         public IHttpHandler GetHttpHandler(RequestContext requestContext)  
  4.         {  
  5.             return new MvcHandler(requestContext);  
  6.         }  
  7.     }  

2.MvcHandler

整个ASP.NET MVC框架是通过自定义的HttpModuleHttpHandlerASP.NET进行扩展构建起来的,这个自定义的HttpModule类型就是UrlRouteModule,而这个自定义的HttpHandler类型则是需要重点介绍的MvcHandler

UrlRouteModule在利用路由表对当前请求实施路由解析并得到封装路由数据的RouteData对象后,会调用其RouteHandlerGetHttpHandler方法得到一个HttpHandler对象,然后将其映射到当前的HTTP上下文。由于RouteDataRouteHandler来源于对应Route对象的RouteHandler,而后者在默认的情况下是一个MvcRouteHandler对象,所有默认情况下用于处理HTTP请求的就是这么一个MvcHandler对象。MvcHandler实现了对Controller对象的激活和对目标Action方法的执行。

如下面的代码片段所示,MvcHandler具有一个类型为RequestContext的属性,它表示当前请求上下文,该属性在构造函数中指定。MvcHandlerProcessRequest方法中实现了对Controller对象的激活和执行。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MvcHandler : IHttpHandler  
  2.     {  
  3.         public bool IsReusable  
  4.         {  
  5.             get { return false; }  
  6.         }  
  7.         public RequestContext RequestContext { get; private set; }  
  8.    
  9.         public MvcHandler(RequestContext requestContext)  
  10.         {  
  11.             this.RequestContext = requestContext;  
  12.         }  
  13.    
  14.         public void ProcessRequest(HttpContext context)  
  15.         {  
  16.             string controllerName = this.RequestContext.RouteData.Controller;  
  17.             IControllerFactory controllerFactory = ControllerBuilder.Current.GetControllerFactory();  
  18.             IController controller = controllerFactory.CreateController(this.RequestContext, controllerName);  
  19.             controller.Execute(this.RequestContext);  
  20.         }  
  21.     }  


3.ControllerControllerFactory

我们为Controller定义了一个接口IController。如下所示,该接口具有唯一的方法Execute表示对当前Controller对象的执行。该方法在MvcHandlerProcessRequest方法中被调用,而传入该方法的参数是表示当前请求上下文的RequestContext对象。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public interface IController  
  2.     {  
  3.         void Execute(RequestContext requestContext);  
  4.     }  

MvcHandler的定义可以看到,Controller对象的激活是通过工厂模式实现的,我们为激活Controller的工厂定义了IControllerFactory接口。该接口具有唯一的方法CreateController,该方法根据当前请求上下文和通过路由解析得到的目标Controller的名称激活相应的Controller对象。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public interface IControllerFactory  
  2.    {  
  3.        IController CreateController(RequestContext requestContext, string controllerName);  
  4.    }  

MvcHandlerProcessRequest方法中,他通过ControllerBuilder的静态属性Current得到当前的ControllerBuilder对象,并调用其GetControllerFactory方法获得当前的ControllerFactory。接下来MvcHandler通过从RequestContext中提取的RequestData对象获得目标Controller的名称,最后将它连同RequestContext一起作为参数调用ControllerFactoryCreateController方法实现对目标Controller对象的创建。

ControllerBuilder的整个定义如下,表示当前ControllerBuilder的静态只读属性Current在静态构造函数中被创建,其SetControllerFactoryGetControllerFactory方法用于ControllerFactory的注册和获取。

 

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class ControllerBuilder  
  2.     {  
  3.         private Func<IControllerFactory> factoryThunk;  
  4.         public static ControllerBuilder Current { get; private set; }  
  5.    
  6.         static ControllerBuilder()  
  7.         {  
  8.             Current = new ControllerBuilder();  
  9.         }  
  10.    
  11.         public IControllerFactory GetControllerFactory()  
  12.         {  
  13.             return factoryThunk();  
  14.         }  
  15.    
  16.         public void SetControllerFactory(IControllerFactory controllerFactory)  
  17.         {  
  18.             factoryThunk = () => controllerFactory;  
  19.         }  
  20.     }  

在之前我们建立在自定义ASP.NET MVC框架的Web应用,我们就是通过当前的ControllerBuilder来注册ControllerFactory。注册的ControllerFactory类型为DefaultControllerFactory

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Global : System.Web.HttpApplication  
  2.     {  
  3.         protected void Application_Start(object sender, EventArgs e)  
  4.         {  
  5.             ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory());  
  6.         }  
  7.     }  


作为默认ControllerFactoryDefaultControllerFactory类型定义如下。由于激活Controller对象的前提是能够正确的解析出Controller的真实类型,作为CreateController方法输入参数的controllerName仅仅表示Controller的名称,所以我们需要加上Controller字符后缀作为类型名称。在DefaultControllerFactory类型被加载的时候(静态构造函数被调用),他通过BuilderMessage加载所有被引用的程序集,得到所有实现了接口的IController的类型并将其缓存起来。在CreateController方法中,DefaultControllerFactory根据Controller的名称从保存的Controller类型列表中得到对应的Controller类型,并通过反射的方式创建它。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class DefaultControllerFactory : IControllerFactory  
  2.     {  
  3.         private static List<Type> controllerTypes = new List<Type>();  
  4.    
  5.         static DefaultControllerFactory()  
  6.         {  
  7.             foreach (Assembly assembly in BuildManager.GetReferencedAssemblies())  
  8.             {  
  9.                 foreach (Type type in assembly.GetTypes().Where(type => typeof(IController).IsAssignableFrom(type)))  
  10.                 {  
  11.                     controllerTypes.Add(type);  
  12.                 }  
  13.             }  
  14.         }  
  15.    
  16.         public IController CreateController(RequestContext requestContext,string controllerName)  
  17.         {  
  18.             string typeName = controllerName + "Controller";  
  19.             Type controllerType = controllerTypes.FirstOrDefault(c => string.Compare(typeName, c.Name, true) == 0);  
  20.             if (null == controllerType)  
  21.             {  
  22.                 return null;  
  23.             }  
  24.             return (IController)Activator.CreateInstance(controllerType);  
  25.         }  
  26.     }  

上面我们详细地介绍了 Controller 的激活原理,现在将关注点返回到 Controller 自身。我们通过实现 IController 接口为所有的 Controller 定义了一个具有如下定义的 ControllerBase 抽象基类,从中可以看到在实现的 Execute 方法中 ControllerBase 通过一个实现了接口 IActionInvoker 的对象完成了针对 Action 方法的执行。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public abstract class ControllerBase : IController  
  2.     {  
  3.         protected IActionInvoker ActionInvoker { get; set; }  
  4.    
  5.         public ControllerBase()  
  6.         {  
  7.             this.ActionInvoker = new ControllerActionInvoker();  
  8.         }  
  9.    
  10.         public void Execute(RequestContext requestContext)  
  11.         {  
  12.             ControllerContext context = new ControllerContext  
  13.             {  
  14.                 RequestContext = requestContext,  
  15.                 Controller = this  
  16.             };  
  17.             string actionName = requestContext.RouteData.ActionName;  
  18.             this.ActionInvoker.InvokeAction(context, actionName);  
  19.         }  
  20.     }  
在下一章我们讲解Action的执行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蒋金楠编*的《ASP.NET MVC5框架揭秘》以一个 模拟ASENET MVC内部运行机制的“迷你版MVC框架” 作为开篇,其目的在于将ASENET MVC真实架构的“全 景”勾勒出来。接下来本书以请求消息在ASENET MVC 框架内部的流向为主线将相关的知识点串联起来,力 求将“黑盒式”的消息处理管道清晰透明地展示在读 者面前。相信精读本书的读者一定能够将ASENET MVC :从接收请求到 响应回复的整个流程了然于胸,对包 括路由、Controller的激活、Model元数据的解析、 Action方法的选择与执行、参数的绑定与验证、过滤 器的执行及View的呈现等相关机制具有深刻的理解。   本书以实例演示的方式介绍了很多与ASENET MVC 相关的*佳实践,同时还提供了一系列实用性的扩展 ,相信它们一定能够解决你在真实开发过程中遇到的 很多问题。本书*后一章提供的案例不仅用于演示实 践中的ASENET MVC很多架构设计方面的东西也包含其 中。除此之外,本书在很多章节还从设计的角度对 ASENET MVC的架构进行了深入分析,所以从某种意义 上讲本书可以当成一本架构设计的书来读。   虽然与市面上任何一本相关的书相比,本书走得 *远,并*加近距离地触及ASENET MVC框架的内核, 但是就其内容本身来讲却没有涉及太多“高深莫测” 的知识点,所以阅读本书不存在太高的门槛。如果你 觉得自己对ASENET MVC所知甚少,可以利用此书来系 统地学习ASENET MVC;如果你觉得自己对ASENET MVC足够精通,一定能够在此书中找到相应的“盲点 ”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值