asp.net Controller学习一

1.Controller类

   Controller的执行体现在对其Excute方法的调用,在IController这个接口里只定义了一个Excute方法,这个方法是以同步的方式执行的。

public interface IController{ void Excute(RequestContext RequestContext);}

   为了异步方式,在System.Web.Mvc.Async命名空间下定义了一个IAsyncController的接口,如下面代码所示

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

   IAsyncController接口派生于IController接口,Controller异步执行通过先后调用BeginExcute和EndExecute方法。还有一个非常重要的基类ControllerBase,默认所有的Controller类都会继承它,它是一个抽象类,ControllerBase也实现了IController接口。这个类显示的实现了接口的Excute方法,这个实现的Excute方法会调用受保护的虚方法Excute,后者将继续调用抽象方法ExcuteCore方法,作为ControllerBase的继承者,必须通过ExcuteCore方法来完成Controller的执行。以下是ControllerBase的代码片段

        public abstract class ControllerBase : IController
        {
            public ViewDataDictionary ViewData { get; set; }
            public dynamic ViewBag { get; }
            public TempDataDictionary TempData { get; set; }
protected virtual void Execute(RequestContext requestContext); protected abstract void ExecuteCore(); protected virtual void Initialize(RequestContext requestContext); void IController.Execute(RequestContext requestContext); }

    目标Controller在执行后会返回一个View作为响应,此时Controller可以通过TempData、ViewBag、ViewData向View传值。从定义可以看到TempData和ViewData均返回字典结构的数据容器,两者不同的地方是TempData如其名字,存储的数据是暂时的,用过一次后就不能再用了,ViewData则可以多次使用。ViewBag则是可以存储动态对象,也就是可以指定任何属性,属性名则为数据字典的Key。还有ControllerContext这个类,这个类的对象可以看做是RequestContext和Controller对象的封装。从上面ControllerBase类的定义可以看到还有一个Initialize方法,该方法具有一个RequestContext的参数,这个方法被执行的时候就会创建ControllerContext对象。受保护的虚方法Excute在执行ExcuteCore方法前就先执行Initialize方法。我们通过VS创建的控制器实际上继承自抽象的Controller类,在VS里可以看到Controller除了继承ControllerBase类,实现IController接口和IAsyncController接口外,还实现了5种过滤器的接口。除此之外,它还实现了一些其他接口,比如IDisposable接口,MVC的Controller激活系统在Controller执行结束后会调用其Dispose方法完成相应的资源回收工作。

2.同异步、ControllerFactory、ControllerBuilder

   从抽象类Controller的定义可以看出它实现了IAsyncControll接口,而这个接口又继承自接口IController接口,因此Controller既可以实现同步的方式(Excute),也可以实现异步的方式(BeginExcute/EndExcute方法)。Controller类有一个DisableAsyncSupport属性,默认是false,如果设置它为true则它只以同步的方式执行,为false时是异步方式执行。

   ASP.NET MVC为Controller的激活定义了相应的工厂,即ControllerFactory类,所有的ControllerFactory类都实现了IControllerFactory接口,如下面代码片段

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

   ControllerFactory将负责创建和释放Controller对象的工作。创建体现在CreateController这个方法中,释放则是ReleaseController方法中。还有一个GetControllerSessionBehavior方法返回类型为SessionStateController的枚举值。其4个属性为:Default,表示使用默认ASP.NET逻辑来确定请求的会话状态行为;Requeired为请求启用完全的读/写会话状态行为;ReadOnly:为请求启用只读会话状态行为;Disabled禁用会话状态。具体采用何种行为取决于http上下文,HttpContext的静态属性Current。

   用于激活Controller对象的ControllerFactory最终是通过ControllerBuilder注册到ASP.NET MVC框架里的。

    public class ControllerBuilder
    {
        public ControllerBuilder();
        public static ControllerBuilder Current { get; }
        public HashSet<string> DefaultNamespaces { get; }

        public IControllerFactory GetControllerFactory();
        public void SetControllerFactory(IControllerFactory controllerFactory);
        public void SetControllerFactory(Type controllerFactoryType);
    }

    ControllerBuilder的Current返回当前使用的对象,两个重载的SetControllerFactory方法实现ControllerFactory的注册,不同的是第一个注册的是一个具体的ControllerFactory对象,第二个注册的是一个ControllerFactory的类型。如果我们注册采用第二种方式,那么GetControllerFactory在执行时通过调用Activator的静态方法CreateInstance的方式来创建对象,也就是说这种情况下每次调用GetControllerFactory方法总是伴随着对象的实例化,然而MVC机制并不会对实例的对象进行缓存。因此采用第一种方式比较好,这样会得到具体的对象直接从GetControllerFactory返回。

    我们知道路由系统对请求实施解析后会生成RouteData对象,它的Values属性保存着目标Controller的名称,如果不指定命名空间时又有同名的控制器名,则会报异常。Controller激活系统为我们提供了2种提升命名空间优先级的方式:第一种则是在注册路由时指定,此时命名空间列表保存在Route对象的DataTokens属性表示的RouteValueDictionary对象中(这个地方还可以指定后备命名空间);另一种方式则是在ControllerBuilder指定DefaultNamespaces属性,ControllerBuilder.Current.DefaultNamespaces.Add("命名空间")。不过前者具有较高的优先级。

3.Controller的激活与路由

   路由系统可以看成是请求被IIS分发给ASP.NET管道后的第一道屏障,接下来学习Controller的激活系统与路由系统是如何有机的结合起来。由前面的知识我们知道,整个ASP.NET的路由系统建立在一个叫做UrlRoutingModule的HttpModule之上,它会通过注册HttpApplication为当前当前的请求动态的地映射一个HttpHandler。也就是通过全局路由表对请求实施路由解析并生成一个RouteData对象,然后借助这个对象的RouteHandler得到最终被映射到当前请求的HttpHandler。RouteHandler对象在MVC机制里是一个MvcRouteHandler对象。那么,我们可以看到最简单的本质,那就是RouteData的MvcRouteHandler对象创造出了HttpHandler对象。我们来看一下MvcRouteHandler,

    public class MvcRouteHandler : IRouteHandler
    {
        public MvcRouteHandler();
        public MvcRouteHandler(IControllerFactory controllerFactory);

        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext);
        protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext);
    }

   MvcRouteHandler里维护着ControllerFactory对象,该对象在构造函数指定,如果没有指定则会调用当前ControllerBuilder对象的GetControllerFactory方法得到。除了得到HttpHandler对象外,MvcRouteHandler还会设置当前http的会话状态,该方法会先从RequestContext的RouteData对象拿到目标Controller的名称,这个名称和RequestContext对象会作为参数调用ControllerFactory的GetControllerSessionBehavior方法得到类型为SessionStateBehavior的枚举,最后再对会话状态进行设置。RouteData的RouteHandler属性最初来源于对应的路由对象,对于调用RouteCollection的扩展方法MapRoute注册的Route对象来说,它对应的RouteHandler就是一个MvcRouteHandler对象,由于在创建这个对象时并没有显示指定ControllerFactory,因此通过调用当前ControllerBuilder对象的GetControllerFactory方法的得到的ControllerFactory会默认被使用。

   GetHttpHandler方法里最后会retutn new MvcHandler(requestContext);,通过ControllerBuilder的GetControllerFactory方法的ControllerFactory仅仅被MvcRouteHandler用来获取会话状态模式而已,而只有MvcHandler才是真真的创建目标Controller对象。由于MvcHandler同时实现了IHttpHandler和IHttpAsyncHandler接口,所有它总是以异步方式执行的,最终激活Controller的工作是由当前ControllerBuilder提供的ControllerFactory对象激活目标Controller对象。最后MvcHandler会实施释放清理工作。

   

你可能感兴趣的:(asp.net Controller学习一)