Asp.net MVC-3-执行过程
本篇主要讲述MVC处理请求时创建Controller和执行Action的完整过程。
创建Controller
先查看MvcHandler中处理请求的方法BeginProcessRequest:
protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
IAsyncController asyncController = controller as IAsyncController;
if (asyncController != null)
{
……
}
else
{
……
}
}
再查看其中创建Controller的方法ProcessRequestInit
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
HttpContext currentContext = HttpContext.Current;
……
AddVersionHeader(httpContext);
RemoveOptionalRoutingParameters();
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
……
}
Controller通过ControllerBuilder属性的方法GetControllerFactory获取到ControllerFactory对象然后由ControllerFactory创建,ControllerBuilder属性定义如下。
internal ControllerBuilder ControllerBuilder
{
get
{
if (_controllerBuilder == null)
{
_controllerBuilder = ControllerBuilder.Current;
}
return _controllerBuilder;
}
set { _controllerBuilder = value; }
}
可知ControllerBuilder默认使用ControllerBuilder.Current,查看ControllerBuilder类的代码:
public IControllerFactory GetControllerFactory()
{
return _serviceResolver.Current;
}
internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
{
_serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>( () => _factoryThunk(),new DefaultControllerFactory { ControllerBuilder = this }, "ControllerBuilder.GetControllerFactory");
}
可知默认返回的ControllerFactory为DefaultControllerFactory(当然我们也可以注册默认的自定义的ControllerFactory),这里我们可继续查看DefaultControllerFactory
internal DefaultControllerFactory(……)
{
……
_activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
() => null,
new DefaultControllerActivator(dependencyResolver),
"DefaultControllerFactory constructor");
}
}
private IControllerActivator ControllerActivator
{
get
{
if (_controllerActivator != null)
{
return _controllerActivator;
}
_controllerActivator = _activatorResolver.Current;
return _controllerActivator;
}
}
public virtual IController CreateController(RequestContext requestContext, string controllerName)
{
……
Type controllerType = GetControllerType(requestContext, controllerName);
IController controller = GetControllerInstance(requestContext, controllerType);
return controller;
}
protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
……
return ControllerActivator.Create(requestContext, controllerType);
}
可以看到最终Controller由DefaultControllerActivator来创建
public DefaultControllerActivator(IDependencyResolver resolver)
{
if (resolver == null)
{
_resolverThunk = () => DependencyResolver.Current;
}
else
{
_resolverThunk = () => resolver;
}
}
public IController Create(RequestContext requestContext, Type controllerType)
{
try
{
return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
}
catch (Exception ex)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.DefaultControllerFactory_ErrorCreatingController,
controllerType),
ex);
}
}
到此为止Controller就被创建出来了,这里我们看到了DependencyResolver.Current,这是MVC的默认注入容器,如果设置了容器,Controller的创建就可以通过容器(GetService)来完成了,如果未实现DependencyResolver或DependencyResolver未注册该Controller则通过反射来创建(使用Activator.CreateInstance,必须存在无参构造函数)。
Controller注入
下面来看对框架的第一个扩展也是最基本的扩展:为框架提供Ioc容器并注册Controller。对于Ioc容器的起源和作用这里就不多讲了。目前Ioc的思想已经普遍地应用于各种开发实践当中了,特别是企业应用开发中,Spring已经是Java开发事实上的基础框架。Asp.net Mvc也深受影响,虽然框架本身没有提供Ioc容器的实现,但是提供了很方便的扩展方式,通过扩展我们不仅可以使用容器管理自定义的对象,甚至可以将对象注入到Mvc框架当中(简单的比如对Controller的注入)。因为Mvc框架默认首先通过容器来获取对象,然后才是框架提供的方式(一般是一种默认实现),在以后的分析中可以看到许多的源码都可以证实这一点。
下面我们通过添加Autofac来实现依赖注入。
首先通过nuget添加Autofac和Autofac.Mvc5的引用。
在App_Start目录下添加Autofac的初始化类如下:
public class AutofacConfig
{
public static IDependencyResolver GeResolver()
{
var builder = new ContainerBuilder();
Registers(builder);
builder.RegisterControllers(Assembly.GetExecutingAssembly());
return new AutofacDependencyResolver(builder.Build());
}
private static void Registers(ContainerBuilder builder)
{
}
}
然后在Global.asax的Application_Start方法中添加代码如下:
DependencyResolver.SetResolver(AutofacConfig.GeResolver());
这样我们就完成了依赖注入(目前只是Controller的注入,当然以后可以AutofacConfig 的Registers方法中把我们需要注入的对象注入到Autofac容器中)。关于依赖注入需要注意的主要有两点:一个是ContainerBuilder的扩展方法RegisterControllers,其参数类型为params Assembly[]可以传入一个或多个Assembly然后注册这些Assembly里的Controller,这样我们就可以将Controller放到不同的工程里;另一个是DependencyResolver.SetResolver,这样会替换掉默认的DependencyResolver实现,我们正是通过这样把Autofac容器作为了Mvc的容器从而完成依赖注入。
下面通过一个简单的例子说明Ioc容器的应用。首先创建一个简单的接口及其实现的类
public interface IIocTest
{
string Say();
}
public class IocTest: IIocTest
{
public string Say()
{
return "IocTest";
}
}
然后再HomeController中添加一个该接口的字段,并创建一个构造函数用于注入(AutoFac默认只支持构造函数注入,但也可以开启属性注入)。
private IIocTest iocTestInsatnce;
public HomeController(IIocTest iocTest)
{
iocTestInsatnce = iocTest;
}
然后再一个Action中调用接口方法,然后通过ViewBag(或其它方法)将其传到页面并显示,页面显示有多种方法,这里直接加到标题中:
public ActionResult Index()
{
ViewBag.iocSays = iocTestInsatnce.Say();
return View();
}
@{
ViewBag.Title = "Home Page"+ ViewBag.iocSays;
}
然后运行程序,查看相应页面的标题,验证注入是否成功。
执行Action
创建好Controller之后我们再来看Controller是如何执行请求的。
首先看ControllerBase,这是所有Controller的基类,查看它的处理方法BeginExecuteCore。
protected virtual IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
……
try
{
string actionName = GetActionName(RouteData);
IActionInvoker invoker = ActionInvoker;
IAsyncActionInvoker asyncInvoker = invoker as IAsyncActionInvoker;
if (asyncInvoker != null)
{
BeginInvokeDelegate<ExecuteCoreState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, ExecuteCoreState innerState)
{
return innerState.AsyncInvoker.BeginInvokeAction(innerState.Controller.ControllerContext, innerState.ActionName, asyncCallback, asyncState);
};
EndInvokeVoidDelegate<ExecuteCoreState> endDelegate = delegate(IAsyncResult asyncResult, ExecuteCoreState innerState)
{
if (!innerState.AsyncInvoker.EndInvokeAction(asyncResult))
{
innerState.Controller.HandleUnknownAction(innerState.ActionName);
}
};
ExecuteCoreState executeState = new ExecuteCoreState() { Controller = this, AsyncInvoker = asyncInvoker, ActionName = actionName };
return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, executeState, _executeCoreTag);
}
else
{
……
}
}
……
}
可以看到Action的执行通过ActionInvoker. BeginInvokeAction实现,ActionInvoker的获取方式如下:
protected virtual IActionInvoker CreateActionInvoker()
{
return Resolver.GetService<IAsyncActionInvoker>() ?? Resolver.GetService<IActionInvoker>() ?? new AsyncControllerActionInvoker();
}
这里也看到了Resolver即可以通过Ioc容器来提供IAsyncActionInvoker或IActionInvoker,如果未提供则使用默认的AsyncControllerActionInvoker,再查看默认的实现AsyncControllerActionInvoker的处理方法BeginInvokeAction。
public virtual IAsyncResult BeginInvokeAction(ControllerContext controllerContext, string actionName, AsyncCallback callback, object state)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
Contract.Assert(controllerContext.RouteData != null);
if (String.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())
{
throw Error.ParameterCannotBeNullOrEmpty("actionName");
}
ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);
if (actionDescriptor != null)
{
FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
Action continuation = null;
BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState)
{
try
{
AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext,
filterInfo.AuthenticationFilters, actionDescriptor);
if (authenticationContext.Result != null)
{
AuthenticationChallengeContext challengeContext =
InvokeAuthenticationFiltersChallenge(controllerContext,
filterInfo.AuthenticationFilters, actionDescriptor, authenticationContext.Result);
continuation = () => InvokeActionResult(controllerContext,
challengeContext.Result ?? authenticationContext.Result);
}
else
{
AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
if (authorizationContext.Result != null)
{
AuthenticationChallengeContext challengeContext =
InvokeAuthenticationFiltersChallenge(controllerContext,
filterInfo.AuthenticationFilters, actionDescriptor, authorizationContext.Result);
continuation = () => InvokeActionResult(controllerContext,
challengeContext.Result ?? authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
{
ValidateRequest(controllerContext);
} IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
IAsyncResult asyncResult = BeginInvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters, asyncCallback, asyncState);
continuation = () =>
{
ActionExecutedContext postActionContext = EndInvokeActionMethodWithFilters(asyncResult);
AuthenticationChallengeContext challengeContext =
InvokeAuthenticationFiltersChallenge(controllerContext,
filterInfo.AuthenticationFilters, actionDescriptor,
postActionContext.Result);
InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters,
challengeContext.Result ?? postActionContext.Result);
};
return asyncResult;
}
}
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception ex)
{
ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
{
throw;
}
continuation = () => InvokeActionResult(controllerContext, exceptionContext.Result);
}
return BeginInvokeAction_MakeSynchronousAsyncResult(asyncCallback, asyncState);
};
EndInvokeDelegate<bool> endDelegate = delegate(IAsyncResult asyncResult)
{
try
{
continuation();
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception ex)
{
ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
{
throw;
}
InvokeActionResult(controllerContext, exceptionContext.Result);
} return true;
};
return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _invokeActionTag);
}
else
{
return BeginInvokeAction_ActionNotFound(callback, state);
}
}
这是一个非常重要的方法,也是我们后续分析的基础,它描述了我们主要的处理流程。此方法中关联了相当多的类,但是其主要处理流程是容易清晰明白的。大致是先获取ControllerDescriptor和ActionDescriptor,然后依次执行Action中的过滤器AuthenticationFilters、AuthorizationFilters来进行验证和授权检查,然后是页面安全检查、获取参数,然后执行ActionFilter和Action,整个过程中如果设置了Result会直接执行AuthenticationFilters的AuthenticationFiltersChallenge,然后执行ResultFilters对结果进行过滤,当然如果处理过程中抛出异常会调用ExceptionFilter进行处理。如果要理解处理的细节需要查看大量的源码,这里提供一点小小的参考ReflectedActionDescriptor、ReflectedControllerDescriptor为ActionDescriptor和ControllerDescriptor的默认实现,Action、过滤器等的查找实际都是通过反射类获取的。
下面为BeginInvokeAction的处理过程图

Asp.net MVC-3-执行过程的更多相关文章
- Asp.net Mvc 过滤器执行顺序
Asp.net Mvc 过滤器执行顺序: IAuthorizationFilter(OnAuthorization)----->IActionFilter(OnActionExecuting)- ...
- 基于ASP.NET MVC定时执行任务调度
相对FluentScheduler实现定时调度任务的使用简单,配置少的特点,Quartz.Net则配置稍微复杂一些.下面我们就接合一个 ASP.NET MVC网站应用程序的定时执行任务调试的小实例来了 ...
- ASP.NET MVC创建视图过程
MvcHandler.ProcessRequest() (1)获取Action执行结果:context2.Result ActionExecutedContext context2 = this. ...
- ASP.NET的页面执行过程
对于ASP.NET来说,用户访问的页面,都由服务器IIS处理,具体的处理过程如下图: 对于用户模块还是有很多的东西没有写,未完待续...
- 迷你版mvc框架执行过程
一.把路由添加到路由表, 二.注册ControllerBuilder(老板)和默认工厂(DefaultControllerFactory) 2.1默认工厂获取可以创建的Controller. 三.由于 ...
- MVC执行过程
HttpRuntime中的PR方法1,封装HttpContext2,获取HttpApplication 主要做3件事a,执行本事件时主要调用Init将Global编译得到类型,b,确保Appstart ...
- 新作《ASP.NET MVC 5框架揭秘》正式出版
ASP.NET MVC是一个建立在ASP.NET平台上基于MVC模式的Web开发框架,它提供了一种与Web Form完全不同的开发方式.ASP.NET Web Form借鉴了Windows Form基 ...
- 1.3 ASP.NET MVC生命周期
ASP.NET MVC的执行生命周期主要分为三个阶段,分别是网址路由对比.执行控制器与动作.执行视图并返回结果.从ASP.NET MVC接受HTTP请求到返回HTTP响应的过程如下图所示.
- ASP.NET没有魔法——ASP.NET MVC 过滤器(Filter)
上一篇文章介绍了使用Authorize特性实现了ASP.NET MVC中针对Controller或者Action的授权功能,实际上这个特性是MVC功能的一部分,被称为过滤器(Filter),它是一种面 ...
- [ASP.NET MVC]视图是如何呈现的
为了搞清楚ASP.NET MVC的请求过程,我们计划从结果追踪到源头.使用VS2012创建一个空白的ASP.NET MVC项目 然后创建一个HelloController 创建一个HelloView. ...
随机推荐
- android相对布局中控件的常用属性【转】
Android布局属性详解 RelativeLayout用到的一些重要的属性: 第一类:属性值为true或false android:layout_centerHorizontal 水平居中 andr ...
- Vue.js中组件传参的方法 - 基于webpack模板
在Vuejs中, 组件之间的传参是今天第一次接触, 之前写的组件互相之间都是独立的, 弗敢专也, 必以分人 环境: node.js npm vue-cli 以上安装请自行百度 一.项目创建 $ vue ...
- 数据库MySQL纯净卸载
有些人在安装MySQL后,卸载后再次安装时,一直安装不上去,到最后不得不重装系统来安装MySQL.这里教大家如何将MySQL卸载干净,不影响下次安装. 卸载过程 1.停止mysql服务 2.进行卸载 ...
- cpp(第十四章)
1.类的静态成员变量.静态常整型(static const int)变量可以直接在类声明中初始化,静态常变量(static const )需要在类定义文件中初始化, 常变量(const )则在构造函数 ...
- Java web中常见编码乱码问题(二)
根据上篇记录Java web中常见编码乱码问题(一), 接着记录乱码案例: 案例分析: 2.输出流写入内容或者输入流读取内容时乱码(内容中有中文) 原因分析: a. 如果是按字节写入或读取时乱码, ...
- nodejs实战:使用原生nodeJs模块实现静态文件及REST请求解析及响应(基于nodejs6.2.0版本,不使用express等webMVC框架 )
一.准备工作 1.安装nodejs 首先你需要安装nodeJs 那么nodejs官网:http://nodejs.cn/,下载相应版本,一步一步安装. 二.使用nodejs开发服务器后台应用 1.创建 ...
- 文件快速删除工具, 解决你的node_modules
摘要: 还在为删除文件慢烦恼吗?强大工具dlf来帮助你.作为一名前端开发,最常见的就是node_modules,如果dependencies很多,osx系统删除还好,Windows用户就麻烦了.本文分 ...
- 同是办公软件,wps和office有什么区别?
今天完美小编为大家带来的是wps和office有什么区别教程,那么到底有什么区别呢?相信很多朋友都模棱两可,说不出所以然,看看下面的教程,相信你会选择更适合你的那一款软件.一起来看看吧! 1.两者特点 ...
- 12.ThreadPoolExecutor线程池原理及其execute方法
jdk1.7.0_79 对于线程池大部分人可能会用,也知道为什么用.无非就是任务需要异步执行,再者就是线程需要统一管理起来.对于从线程池中获取线程,大部分人可能只知道,我现在需要一个线程来执行一个任 ...
- javascript痛点之四this的指向问题
先看以下例子 1.我们直接调用this看看指向的是谁 alert(this);//指向window 2.在函数中直接调用看看指向的是谁 function fn(){ alert(this); } fn ...