各Controller的继承关系

Controller最重要的是对Execute方法的调用,当目标Controller对象被激活后,对请求的后续处理和最终响应均是通过执行这个Execute方法来完成。它就定义在IController接口中,如下所示:

public interface IController
{
void Execute(RequestContext requestContext);
}

由于定义在IController接口的Execute方法是以同步的方式执行的,为了异步方式,又另定义了一个IAsyncController接口,它派生于IController接口,Controller的异步执行通过先后调用BeginExecute/EndExecute方法来完成。如下所示:

public interface IAsyncController : IController
{
IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state);
void EndExecute(IAsyncResult asyncResult);
}

默认作为所有Controller基类的ControllerBase实现了IController接口,ControllerBase是一个抽像类,它“显示”的实现了IController中的Execute方法,然后它会调用这个类中受保护的虚方法Execute,而后者最终又会调用抽象方法ExecuteCore。如下所示:

public abstract class ControllerBase : IController
{
//省略
public ControllerContext ControllerContext { get; set; } void IController.Execute(RequestContext requestContext)
{
Execute(requestContext);
}
protected virtual void Execute(RequestContext requestContext)
{
//省略
VerifyExecuteCalledOnce();
Initialize(requestContext); using (ScopeStorage.CreateTransientScope())
{
ExecuteCore();
}
} protected abstract void ExecuteCore(); protected virtual void Initialize(RequestContext requestContext)
{
ControllerContext = new ControllerContext(requestContext, this);
}
//省略
}

从上面我们可以看到受保护的虚方法Execute在调ExecuteCore抽像方法之前,会执行受保护的虚方法Initialize方法初始化ControllerContext属性。ControllerContext如下所示:

public class ControllerContext
{
public virtual ControllerBase Controller { get; set; }
public virtual HttpContextBase HttpContext
{
get
{
if (_httpContext == null)
{
_httpContext = (_requestContext != null) ? _requestContext.HttpContext : new EmptyHttpContext();
}
return _httpContext;
}
set { _httpContext = value; }
}
public virtual RouteData RouteData
{
get
{
if (_routeData == null)
{
_routeData = (_requestContext != null) ? _requestContext.RouteData : new RouteData();
}
return _routeData;
}
set { _routeData = value; }
}
public RequestContext RequestContext
{
get
{
if (_requestContext == null)
{
// still need explicit calls to constructors since the property getters are virtual and might return null
HttpContextBase httpContext = HttpContext ?? new EmptyHttpContext();
RouteData routeData = RouteData ?? new RouteData(); _requestContext = new RequestContext(httpContext, routeData);
}
return _requestContext;
}
set { _requestContext = value; }
} public ControllerContext(HttpContextBase httpContext, RouteData routeData, ControllerBase controller)
: this(new RequestContext(httpContext, routeData), controller)
{
}
public ControllerContext(RequestContext requestContext, ControllerBase controller)
{
//省略
RequestContext = requestContext;
Controller = controller;
}
}

顾名思义,ControllerContext就是基于某个Controller对象上下文。从上面我们可以看出ControllerContext主要是对Controller、RequestContext对象的封装。而对RequestContext又是对HttpContext和RouteData的封装。

VS帮我们创建的Controller默认都是继承自抽像类Controller,它是ControllerBase的子类,如下所示:

public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer
{
protected virtual bool DisableAsyncSupport
{
get { return false; }
} IAsyncResult IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
{
return BeginExecute(requestContext, callback, state);
} void IAsyncController.EndExecute(IAsyncResult asyncResult)
{
EndExecute(asyncResult);
}
protected virtual IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
{
if (DisableAsyncSupport)
{
//同步
Action action = () =>
{
Execute(requestContext);
};
//省略
}
else
{
//异步
//省略
}
} protected virtual void EndExecute(IAsyncResult asyncResult)
{
AsyncResultWrapper.End(asyncResult, _executeTag);
} } public interface IAsyncManagerContainer
{
AsyncManager AsyncManager { get; }
}

Controller还显示地实现了IAsyncController接口和ASP.NET MVC 5种过虑器接口,以及一个特别的IAsyncManagerContainer接口,它提供了一个AsyncManger对象为异步操作的执行提供参数传递操作计数和超时控制等功能,除此之外Controller还为我们实现IDispose接口,在Controller执行结束之后会调用其Dispose方法以完成相应的资源回收工作。

从抽像类Controller的定义上来看,它实现了IAsyncController,而IAsyncController继承自IController,这意味着它既可以采用同步(调用Execute方法)又可以采用异步(调用BeginExecute/EndExecute)的方法执行。但是调用BeginExecute/EndExecute方法也不一定是以异步的方式执行。如上代码所示中它有一个DisableAsyncSupport属性,它默认值为False。

在ASP.NET MVC中还定义了一个AsyncController类,从名称上我们可以看出这是一个异步Controller。但这里指的是Action方法的异步,而不是Controller的异步执行。如下所示:

public abstract class AsyncController : Controller
{
}

这是一个继承自抽像类Controller的一个“空”类型,因为在ASP.NET MVC 3.0时,异步的执行是通过XxxAsync/XxxCompleted的形式定义,以这种方式定义的异步Action方法必须定义在继承自AsyncController的类型中。考虑到向后兼容,于是就一直保留了下来。不过在 ASP.NET MVC4.0及以后,提供了新的异步Action方法定义方式。它直接定义在我们创建的继承自抽像Controller类的子类Controller中就好了,Action方法返回类型为Task既可。

 Controller的激活

首先来看一下IControllerFactory接口,如下所示:

public interface IControllerFactory
{
IController CreateController(RequestContext requestContext, string controllerName);
SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
void ReleaseController(IController controller);
}

从上代码我们看到Controller对象的激活最终是通过CreateController方法来完成的。除了负责创建Controller对象外,还需要处理Controller对象的释放,这个定义在ReleaseController方法中。IControllerFactory还定义一个方法 GetControllerSessionBehavior,返回一个枚举类型SessionStateBehavior,它表示请求处理过程中会话状态支持的模式。具体采用何种会话状态模式取决于当前HTTP上下文(通过HttpContext的静态属性Current表示)。在 ASP.NET 3.0及之前的版本,我们是不能对当前HttpContext会话状态模式进行动态修改。ASP.NET 4.0为HttpContext定义了如下SetSessionStateBehavior方法,相同的方法在HttpContextBase、HttpContextWrapper都有定义。

public abstract class HttpContextBase : IServiceProvider
{
public virtual void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior)
{
}
}
public class HttpContextWrapper : HttpContextBase
{
public override void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior)
{
this._context.SetSessionStateBehavior(sessionStateBehavior);
}
} public sealed class HttpContext : IServiceProvider, IPrincipalContainer
{
public void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior)
{
//省略
this.SessionStateBehavior = sessionStateBehavior;
}
}

用于激活Controller对象的ControllerFactory最终是通过ControllerBuilder注册到MVC框架中的,代码如下:

public class ControllerBuilder
{
private static ControllerBuilder _instance = new ControllerBuilder();
public static ControllerBuilder Current
{
get { return _instance; }
}
public ControllerBuilder(): this(null)
{
} internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
{
_serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
() => _factoryThunk(),
new DefaultControllerFactory { ControllerBuilder = this },
"ControllerBuilder.GetControllerFactory");
}
public void SetControllerFactory(IControllerFactory controllerFactory)
{
//省略
_factoryThunk = () => controllerFactory;
} public void SetControllerFactory(Type controllerFactoryType)
{
//省略
_factoryThunk = delegate
{
return (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
};
} public IControllerFactory GetControllerFactory()
{
return _serviceResolver.Current;
}
}

从上代码片段中,我们可以看到一个Current属性返回当前使用的ControllerBuilder对象,以及两个SetControllerFactory方法重载实现针对ControllerFactory的注册和一个GetControllerFactory方法用于获取ControllerFactory对象。 关于两个重载方法,它们的不同之处在于第一个是传入一个IControllerFactory对象,第二个是传入一个IControllerFactory类型。如果是通过第二个的方法注册ControllerFactory,那么我们在每次获取时,都要通过反射获得某个ControllerFactory的实例,MVC将不会对它所创建的Controller进行缓存。而第一个则直接将IControllerFactory对象返回。从性能方面考虑,第一种的方式更好一些,在构造函数中我们也可以看到默认就是通过new一个DefaultControllerFactory对象。

在《简说mvc路由》一文中我们介绍过MVC是通过UrlRoutingModule对HttpApplication上的PostResovleRequestCache事件的注册拦截请求。然后从RouteTable的静态属性Routes中对请求实施路由解析生成一个RouteData对象,然后借助RouteData的RouteHandler属性得到最终的被映射到当前请求的HttpHandler。

public class MvcRouteHandler : IRouteHandler
{
private IControllerFactory _controllerFactory; public MvcRouteHandler()
{
} public MvcRouteHandler(IControllerFactory controllerFactory)
{
_controllerFactory = controllerFactory;
} protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
} protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
{
string controllerName = (string)requestContext.RouteData.Values["controller"];
//省略
IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
}
}

在上一篇文章中,我们知道MVC框架中,对RouteHandler默认实现就是MvcRouteHandler。在MvcRouteHandler中维护着一个ControllerFactory对象,该对象可以在构造函数中指定,如果没有指定,那么它会调用当前ControllerBuilder对象GetControllerFactory方法得到这个对象。在实例化Route时,我们传的是new MvcRouteHandler()时,是调用无参构造函数的,所以在这里_controllerFactory肯定为null,而在上面ControllerBuilder类的代码片段中,Current是通过new了一个ControllerBuilder无参构造函数,所以MVC默认ControllerFactory的实现是DefaultControllerFactory。不过这里获得ControllerFactory只是用于设置会话状态方式。真正获得ControllerFactory用于创建Controller对象体现在MvcHandler的BeginProcessRequest方法中。

接下来我们主要看IHttpHandler的实现类MvcHandler,如下所示:

public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
internal ControllerBuilder ControllerBuilder
{
get
{
if (_controllerBuilder == null)
{
_controllerBuilder = ControllerBuilder.Current;
}
return _controllerBuilder;
}
set { _controllerBuilder = value; }
}
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)
{
// asynchronous controller // Ensure delegates continue to use the C# Compiler static delegate caching optimization.
BeginInvokeDelegate<ProcessRequestState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, ProcessRequestState innerState)
{
try
{
return innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState);
}
catch
{
innerState.ReleaseController();
throw;
}
}; EndInvokeVoidDelegate<ProcessRequestState> endDelegate = delegate(IAsyncResult asyncResult, ProcessRequestState innerState)
{
try
{
innerState.AsyncController.EndExecute(asyncResult);
}
finally
{
innerState.ReleaseController();
}
};
ProcessRequestState outerState = new ProcessRequestState()
{
AsyncController = asyncController, Factory = factory, RequestContext = RequestContext
}; SynchronizationContext callbackSyncContext = SynchronizationContextUtil.GetSynchronizationContext();
return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, outerState, _processRequestTag, callbackSyncContext: callbackSyncContext);
}
else
{
// synchronous controller
Action action = delegate
{
try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
}; return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
}
}
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
//省略
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
//省略
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
//省略
}
}

从上我们可以看到MvcHandler同时实现了IHttpAsyncHandler和IHttpHandler接口,所以它总是以异步的方式被执行(调用BeginProcessRequest和EndProcessRequest方法)。调用ProcessRequestInit方法中,通过RequestContext的RouteData属性获得controller名称,然后通过本类的ControllerBuilder属性获得ControllerFactory类的实例factory,然后通过它获得Controller的对象,然后调用Controller中的Execute方法或异步BeginExecute/EndExecute方法。

关于DefaultControllerFactory创建Controller如下所示:

public class DefaultControllerFactory : IControllerFactory
{
private IControllerActivator ControllerActivator
{
get
{
if (_controllerActivator != null)
{
return _controllerActivator;
}
_controllerActivator = _activatorResolver.Current;
return _controllerActivator;
}
} public virtual IController CreateController(RequestContext requestContext, string controllerName)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
} if (String.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch())
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "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);
}
//省略
}

MVC Controller的激活的更多相关文章

  1. ASP.NET MVC Controller的激活

    最近抽空看了一下ASP.NET MVC的部分源码,顺带写篇文章做个笔记以便日后查看. 在UrlRoutingModule模块中,将请求处理程序映射到了MvcHandler中,因此,说起Controll ...

  2. ASP.NET MVC——Controller的激活

    Controller的激活是根据在路由过程得到的Controller名称来创建对应的Controller对象.相关类如图: Controller激活的过程可通过如下序列图表示: 代码示例如下: str ...

  3. 白话学习MVC(五)Controller的激活

    一.概述 在此系列开篇的时候介绍了MVC的生命周期 , 对于请求的处理,都是将相应的类的方法注册到HttpApplication事件中,通过事件的依次执行从而完成对请求的处理.对于MVC来说,请求是先 ...

  4. Asp.net mvc 中的 Controller 的激活

    Controller 激活是指根据路由系统解析出来的 Controller 的名称创建 控制器(Controller)的过程,这里的控制器泛指实现了 IController 接口的类型 激活过程中的核 ...

  5. ASP.NET MVC Controller激活系统详解1

    一.引言 好久没有写博客了,前一段时间学习了Controller激活的一篇很好的博文(链接),在此做个学习总结. 二.Controller 2.1 IController Controller类型直接 ...

  6. .NET/ASP.NET MVC Controller 控制器(深入解析控制器运行原理)

    阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...

  7. Controller的激活

    Controller的激活 概述 在此系列开篇的时候介绍了MVC的生命周期 , 对于请求的处理,都是将相应的类的方法注册到HttpApplication事件中,通过事件的依次执行从而完成对请求的处理. ...

  8. 二、ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)

    阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...

  9. ASP.NET没有魔法——ASP.NET MVC Controller的实例化与执行

    上一章节中对路由的注册和匹配过程进行了介绍,知道了MVC的Http请求最终是交由MvcHandler处理的,而其处理过程就是对Controller的创建.执行和释放. 本章将从以下几点进一步对上面提到 ...

随机推荐

  1. Hibernate3.3.2_ID生成策略

    1,xml生成id generator:常用四个:native.identity.sequence.uuid. Annotation: 1,@GeneratedValue: a)自定义ID b)AUT ...

  2. 各种height/width总结

    CSS盒模型是比较复杂的,尤其是当页面中有滚动条时,仅仅通过css来操作高度宽度是不够的,幸运的是Javascript提供了不少这样的接口.Javascript中clientHeight / clie ...

  3. 【Qt开发】常用控件--QLineEdit

    QLineEdit是单行文本编辑控件.比如用户名,密码等输入框可以使用该控件. 所属头文件<QLineEdit> 常用方法 1.void setText(const QString &am ...

  4. Leetcode 483. Smallest Good Base

    For an integer n, we call k>=2 a good base of n, if all digits of n base k are 1. Now given a str ...

  5. 动画性能优化-requestAnimationFrame、GPU等

    最近在做一个场景动画,有一个欢迎界面和一个主动画界面,两个界面之间的连接通过一个进度条来完成,当进度条完成,提供通往主动画的按钮. 画面会从一个个的场景移动过去,用户可通过点击抽奖.查看气泡商铺等进行 ...

  6. Ubuntu 安装 Caffe

    Caffe Caffe 安装(Python2 CPU版本) 参考博文https://blog.csdn.net/pangyunsheng/article/details/79418896 安装环境 U ...

  7. 《TCP/IP详解》

    TCP/IP概述 Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本 ...

  8. [转]MongoDB 概念解析

    本文转自:http://www.runoob.com/mongodb/mongodb-databases-documents-collections.html 不管我们学习什么数据库都应该学习其中的基 ...

  9. ayer.prompt 怎样让输入值为空也可以向下执行

    http://fly.layui.com/jie/4227/ layer.prompt({title: '输入任何口令,并确认',formType: 1, //prompt风格,支持0-2value: ...

  10. python_tensorflow_Django实现逻辑回归

    1.工程概要 2.data文件以及input_data文件准备 链接:https://pan.baidu.com/s/1EBNyNurBXWeJVyhNeVnmnA 提取码:4nnl 3.logiss ...