在开始之前,声明一下,由于ASP.NET MVC5正式发布了,后面的分析将基于ASP.NET MVC5最新的源代码。
在前面的内容我们分析了怎样根据路由信息来确定Controller的类型,并最终生成Controller的实例。这一节来了解一下Controller的总体执行分析,以同步执行版本为主。

Controller的继承体系如下图所示:

  

当调用Controller实例的Excecute方法时,实际是调用ControllerBase的Excecute方法,该方法的主要实现代码如下:

 protected virtual void Execute(RequestContext requestContext)
{ VerifyExecuteCalledOnce();
Initialize(requestContext);
using (ScopeStorage.CreateTransientScope())
{
ExecuteCore();
}
}

该方法主要为Action的执行做一些初始化工作,Initialize(requestContext)实例化ControllerContext, ScopeStorage.CreateTransientScope方法初始化临时存储环境,这个储存主要用于页面HtmlHlper类中,具体的后面遇到再分析。最后了调用了抽象方法ExecuteCore,在Controller中实现该方法,我们看看该方法的代码:

 protected override void ExecuteCore()
{
PossiblyLoadTempData();
try
{
string actionName = GetActionName(RouteData);
if (!ActionInvoker.InvokeAction(ControllerContext, actionName))
{
HandleUnknownAction(actionName);
}
}
finally
{
PossiblySaveTempData();
}
}

PossiblyLoadTempData, PossiblySaveTempData这一对方法主要是帮助处理Controller的TempData属性中临时数据的加载和保存,默认是基于SessionStateTempDataProvider,也就是TempData的值默认保存在Session中,我们可以在会话范围内使用TempData。接下来的代码很简单直接就是调用ActionInvoker的InvokeAction方法并传递上下文参数和action名称。ActionInvoker是一个类型为IActionInvoker的属性, 它内部实现调用CreateActionInvoker方法,具体的实现如下:

return Resolver.GetService<IAsyncActionInvoker>() ?? Resolver.GetService<IActionInvoker>() ?? new AsyncControllerActionInvoker();

Resolver默认情况下是没有注册IActionInvoker的,可见默认情况下IActionInvoker的实例是AsyncControllerActionInvoker。我们现在来具体看一下IActionInvoker的继承体系.如下图所示:

在这里我们仅分析同步版本的ControllerActionInvoker的实现。现在来看看其InvokeAction的方法, 这个方法实现比较复杂,主要的代码如下:

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{ //省略检查代码
ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null)
{
FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor); try
{
AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor); if (authenticationContext.Result != null)
{
// An authentication filter signaled that we should short-circuit the request. Let all
// authentication filters contribute to an action result (to combine authentication
// challenges). Then, run this action result.
AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(
controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,
authenticationContext.Result);
InvokeActionResult(controllerContext, challengeContext.Result ?? authenticationContext.Result);
}
else
{
AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
if (authorizationContext.Result != null)
{
// An authorization filter signaled that we should short-circuit the request. Let all
// authentication filters contribute to an action result (to combine authentication
// challenges). Then, run this action result.
AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(
controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,
authorizationContext.Result);
InvokeActionResult(controllerContext, challengeContext.Result ?? authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
{
ValidateRequest(controllerContext);
} IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters); // The action succeeded. Let all authentication filters contribute to an action result (to
// combine authentication challenges; some authentication filters need to do negotiation
// even on a successful result). Then, run this action result.
AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(
controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,
postActionContext.Result);
InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters,
challengeContext.Result ?? postActionContext.Result);
}
}
}
catch (ThreadAbortException)
{
// This type of exception occurs as a result of Response.Redirect(), but we special-case so that
// the filters don't see this as an error.
throw;
}
catch (Exception ex)
{
// something blew up, so execute the exception filters
ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
{
throw;
}
InvokeActionResult(controllerContext, exceptionContext.Result);
} return true;
} // notify controller that no method matched
return false;
}

方法内大致做了以下几件事情:

  1. 调用GetControllerDescriptor方法获取ControllerDescriptor类的实例
  2. 调用FinAction方法获取ActionDescriptor类的实例
  3. 收集应用在Action上所有Filter信息
  4. 执行Filter和对应的Action方法
  5. 执行结果ActionResult并返回, true表示找到Acion, false表示没有匹配的Action

上面的每一条都包含很多处理,这里稍微在较高层解说一下相关的类型,具体的后面每个小节解释一个话题 。

1. ControllerDescriptor和ActionDescriptor分别表示Controller和Action元数据的相关描述类型

2. Filter 是提供了ASP.NET MVC 提供的一种 面向方面(AOP)的编程方式,用于Controler或Action执行前后做一些通用处理,如安全验证,授权,异常处理等.

大概有以下几种Filter类型:

IAuthentiactionFilter 表示自定义验证,这个是ASP.NET MVC5新增的类型, OnAuthentication表示执行验证检查,你也许要更改AuthenticationContext的Principal属性,ASP.NET MVC会检查该属性,发现有更改将使用你设置的Principal, OnAuthenticationChallenge方法有点特别,不管是Action或其它的Filter执行失败或成功都会调用OnAuthenticationChallenge方法(异常除外),OnAuthenticationChallenge方法为你的自定义验证写回Http响应提供机会, 如你也许要改写Http header

public interface IAuthenticationFilter
{
/// <summary>Authenticates the request.</summary>
/// <param name="filterContext">The context to use for authentication.</param>
void OnAuthentication(AuthenticationContext filterContext); /// <summary>Adds an authentication challenge to the current <see cref="ActionResult"/>.</summary>
/// <param name="filterContext">The context to use for the authentication challenge.</param>
void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
}

IAuthenticationFilter表示授权检查

 public interface IAuthorizationFilter
{
void OnAuthorization(AuthorizationContext filterContext);
}

IActionFilter表示Action执行前后做一些处理

 public interface IActionFilter
{
void OnActionExecuting(ActionExecutingContext filterContext);
void OnActionExecuted(ActionExecutedContext filterContext);
}

IResultFilter表示ActionResult执行前后做一些处理

public interface IResultFilter
{
void OnResultExecuting(ResultExecutingContext filterContext);
void OnResultExecuted(ResultExecutedContext filterContext);
}

IExceptionFilter表示异常通用处理

 public interface IExceptionFilter
{
void OnException(ExceptionContext filterContext);
}

Filter的总体执行流程如下图所示:

下一节分析一下ControllerDescriptor和ActionDescriptor

ASP.NET MVC5学习笔记之Controller同步执行架构分析的更多相关文章

  1. ASP.NET MVC5学习笔记之Controller执行ControllerDescriptor和ActionDescriptor

    一. ControllerDescriptor说明 ControllerDescriptor是一个抽象类,它定义的接口代码如下: public abstract class ControllerDes ...

  2. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

  3. ASP.NET MVC5学习笔记01

    由于之前在项目中也使用MVC进行开发,但是具体是那个版本就不是很清楚了,但是我觉得大体的思想是相同的,只是版本高的在版本低的基础上增加了一些更加方便操作的东西.下面是我学习ASP.NET MVC5高级 ...

  4. ASP.NET MVC5学习笔记之Filter提供体系

    前面我们介绍了Filter的基本使用,但各种Filter要在合适的时机运行起来,需要预先准备好,现在看看ASP.NET MVC框架是怎么做的. 一.Filter集合 在ControlerActionI ...

  5. ASP.NET MVC5 学习笔记-1 控制器、路由、返回类型、选择器、过滤器

    [TOC] 1. Action 1.1 新建项目 新建项目->Web->Asp.net Web应用程序,选择MVC,选择添加测试. 在解决方案上右键,选择"管理NuGet程序包& ...

  6. ASP.NET MVC5学习笔记之Filter基本介绍

    Filter是ASP.NET MVC框架提供的基于AOP(面向方面)设计,提供在Action执行前后做一些非业务逻辑通用处理,如用户验证,缓存等.现在来看看Filter相关的一些类型信息. 一.基本类 ...

  7. ASP.NET MVC4学习笔记之Controller的激活

    一. 高层相关类说明 当路由系统根据请求Url收集路由信息后,下一步就要将路由信息传给Controller激活系统,Controller激活系统负责实现了IController接口的Controlle ...

  8. ASP.NET MVC5 学习笔记-2 Razor

    1. Razor @*注释*@ 你在用 @Request.Browser.Browser, 发送邮件给support@qq.com, 转义@@qq @{ var amounts = new List& ...

  9. ASP.NET MVC5学习笔记之Action参数模型绑定基本过程

    当我们在Controller中定义一个Action,通常会定义一个或多个参数,每个参数称为一个模型,ASP.NET MVC框架提供了一种机制称为模型绑定,会尝试自动从请求的信息中实例化每一个模型并赋值 ...

随机推荐

  1. mysql start server faild

    可能没卸载干净...在安装mysql数据库时,如果重新安装,很容易遇见apply security setting error,即在配置mysql启动服务时,在启动apply security set ...

  2. 实时阴影渲染(一):PSSM平行分割阴影图

    PSSM(Parallel Split Shadow Map)平行分割阴影图,是一种根据距离远近采用多个深度纹理渲染阴影的方法 适合用于室外大场景中的平行光比如太阳形成的阴影 本系列需要读者了解基本的 ...

  3. Flash Builder 4.6 BUG 远程访问受阻

    今天调试项目的时候,惊讶的发现在使用RemoteObject进行远程访问时出现奇怪现象,只能在服务器本地实现访问,在其他客户机上提示2048错误,send failed,差点没把我吓死,记得之前测试过 ...

  4. OpenStack和Redis

    前言: 最近开始捣鼓OpenStack了,在用RDO部署OpenStack的时候,发现装了Redis, 遂决定看看OpenStack哪些地方(可以)用到Redis.  Redis作为OpenStack ...

  5. linux查看内存和回收内存

    清理前内存使用情况 free -m free -g echo 1 > /proc/sys/vm/drop_caches 清理后内存使用情况 free -m

  6. ubuntu server unable to resolve host

    cat /etc/resolv.conf (查看resolv.conf中的内容: nameserver 是动态添加的……) #通过添加/etc/resolvconf/resolv.conf.d/bas ...

  7. asp.net(c#)中如何在前端用js写条件查询,且不用调用存储过程

    前端页面(源): <dx:ASPxButton ID="ASPxButton_Select" runat="server" Text="查询&q ...

  8. SQL常用日期转换

    0   或   100   (*)     默认值   mon   dd   yyyy   hh:miAM(或   PM)       1   101   美国   mm/dd/yyyy       ...

  9. Windows phone 8 学习笔记(1) 触控输入(转)

    Windows phone 8 的应用 与一般的Pc应用在输入方式上最大的不同就是:Windows phone 8主要依靠触控操作.因此在输入方式上引入一套全新的触控操作方式,我们需要重新定义相关的事 ...

  10. How to search compound files

    Last week my friend told me that she made a terrible mistake. She conducted raw serch and found no s ...