ASP.NET MVC是如何运行的(4): Action的执行
作为Controller基类ControllerBase的Execute方法的核心在于对Action方法的执行和作为方法返回的ActionResult的执行,两者的执行是通过一个叫做ActionInvoker的组件来完成的。
一、ActionInvoker我们同样为ActionInvoker定义了一个接口IActionInvoker。如下面的代码片断所示,该接口定义了一个唯一的方法InvokeAction用于执行指定名称的Action方法,该方法的第一个参数是一个表示基于当前Controller上下文的ControllerContext对象。
1: public interface IActionInvoker
ControllerContext类型在真正的ASP.NET MVC框架中要负责一些,在这里我们对它进行了简化,仅仅将它表示成对当前Controller和请求上下文的封装,而这两个要素分别通过如下所示的Controller和RequestContext属性表示。
ControllerBase中表示ActionInvoker的同名属性在构造函数中被初始化。在Execute方法中,通过作为方法参数的RequestContext对象创建ControllerContext对象,并通过包含在RequestContext中的RouteData得到目标Action的名称,然后将这两者作为参数调用ActionInvoker的InvokeAction方法。
从前面给出的关于ControllerBase的定义我们可以看到在构造函数中默认创建的ActionInvoker是一个类型为ControllerActionInvoker的对象。如下所示的代码片断反映了整个ControllerActionInvoker的定义,而InvokeAction方法的目的在于实现针对Action方法的执行。由于Action方法具有相应的参数,在执行Action方法之前必须进行参数的绑定。ASP.NET MVC将这个机制成为Model的绑定,而这又涉及到另一个重要的组件ModelBinder。
8: public void InvokeAction(ControllerContext controllerContext, string actionName)
10: MethodInfo method = controllerContext.Controller.GetType().GetMethods().First(m = string.Compare(actionName, m.Name, true) == 0);
14: parameters.Add(this.ModelBinder.BindModel(controllerContext, parameter.Name, parameter.ParameterType));
16: ActionResult actionResult = method.Invoke(controllerContext.Controller, parameters.ToArray()) as ActionResult;
二、ModelBinder
我们为ModelBinder提供了一个如下一个简单的定义,这与在真正的ASP.NET MVC中的同名接口的定义不尽相同。该接口具有唯一的BindModel根据ControllerContext和Model名称(在这里实际上是参数名称)和类型得到一个作为参数的对象。
3: object BindModel(ControllerContext controllerContext, string modelName, Type modelType);
通过前面给出的关于ControllerActionInvoker的定义我们可以看到在构造函数中默认创建的ModelBinder对象是一个DefaultModelBinder对象。由于仅仅是对ASP.NET MVC的模拟,定义在自定义的DefaultModelBinder中的Model绑定逻辑比ASP.NET MVC中同名类型中实现的要简单得多。
如下面的代码片断所示,绑定到参数上的数据具有三个来源:HTTP-POST Form、RouteData和Values和DataTokens,它们都是字典结构的数据集合。如果参数类型为字符串或者简单的值类型,我们直接根据参数名称和Key进行匹配;对于复杂类型(比如之前例子中定义的包含Contrller和Action名称的数据类型SimpleModel),则通过反射根据类型创建新的对象并根据属性名称与Key的匹配关系对相应的属性进行赋值。
3: public object BindModel(ControllerContext controllerContext, string modelName, Type modelType)
8: if (GetValueTypeInstance(controllerContext, modelName, modelType, out instance))
17: if (!property.CanWrite || (!property.PropertyType.IsValueType property.PropertyType!= typeof(string)))
22: if (GetValueTypeInstance(controllerContext, property.Name, property.PropertyType, out propertyValue))
29: private bool GetValueTypeInstance(ControllerContext controllerContext, string modelName, Type modelType, out object value)
35: key = form.AllKeys.FirstOrDefault(k = string.Compare(k, modelName, true) == 0);
48: value = Convert.ChangeType(controllerContext.RequestContext.RouteData.Values[key], modelType);
57: value = Convert.ChangeType(controllerContext.RequestContext.RouteData.DataTokens[key], modelType);
在ControllerActionInvoker的InvokeAction方法中,我们直接将传入的Action名称作为方法名从Controller类型中得到表示Action操作的MethodInfo对象。然后遍历MethodInfo的参数列表,对于每一个ParameterInfo对象,我们将它的Name和ParameterType属性表示的参数名称和类型连同创建ControllerContext作为参数调用ModelBinder的BindModel方法并得到对应的参数值。最后通过反射的方式传入参数列表并执行MethodInfo。和真正的ASP.NET MVC一样,定义在Contrller的Action方法返回一个ActionResult对象,我们通过指定它的Execute方法是先对请求的响应。
三、ActionResult我们为具体的ActionResult定义了一个ActionResult抽象基类。如下面的代码片断所示,该抽象类具有一个参数类型为ControllerContext的抽象方法ExecuteResult,我们最终对请求的响应就实现在这里。
在之前创建的例子中,Action方法返回的是一个类型为RawContentResult的对象。顾名思义,RawContentResult将初始化时指定的内容(字符串)原封不动地写入针对当前请求的HTTP回复中,具体的实现如下所示。
ASP.NET MVC是如何运行的[1]: 建立在“伪”MVC框架上的Web应用
ASP.NET MVC是如何运行的[2]: URL路由
ASP.NET MVC是如何运行的[3]: Controller的激活
ASP.NET MVC是如何运行的[4]: Action的执行
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 原文链接
基于Asp.Net Mvc开发的个人博客系统 一个基于Mvc 5构建的简单、代码层级分明的开源个人博客系统。前端美观大气、后台采用RightControl .NET通用角色权限系统,开发简单、效率高。网站配置采用XML配置,灵活可以根据自己是需求进行个性化配置。系统功能完备,完全可以满足需求,基本不用二次开发,非常使用程序员的个人博客。
Java Spring Boot开发实战系列课程【第7讲】:Spring Boot 2.0安全机制与MVC身份验证实战(Java面试题) 立即下载
相关文章
- RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2-模块管理按子系统进行分类管理
- ASP.NET 判断客户端是否为手机的函数
- C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 密码强化、网络安全强化
- 在Asp.Net Core中使用DI的方式使用Hangfire构建后台执行脚本
- Asp.Net_EF Code Frist 执行 nuget命令
- ASP.NET Core 企业开发架构概述
- Asp.Net_的传值跟存储值操作
- Asp.Net_Mvc4_mvc4跟mysql语法
- ASP.NET WEB API 中的路由调试与执行过程跟踪
- asp.net 运行时, 报控件不存在
- 解析大型.NET ERP系统 通用附件管理功能
- 如何解决ASP.NET网站'__doPostBack' is undefined的脚本错误
- 使用ASP.Net WebAPI构建REST服务(四)——参数绑定
- ASP.NET Core部署在IIS上
- Windows server 2003 + IIS6 搭建Asp.net MVC执行环境
- ASP.NET Core – Data Protection & Azure Storage + Azure Key Vault
- 在asp.net中执行存储过程(转)
- ASP.Net MVC_DotNetZip简单使用方法,解决文件压缩的问题[转]
- ASP.NET Web API 如何通过程序控制返回xml还是json
- Allegro批量复制Via并保持net属性
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
- ASP.NET Core的配置(4):多样性的配置来源[下篇]
- 如何让ASP.NET Web API的Action方法在希望的Culture下执行
- ASP.Net .Net4.0 HTTP 错误 404.17 - Not Found
- ASP.NET MVC系列:Model
- ASP.NET core webapi jquery请求 _平台:windows (7)
- 《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf