• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

白话ASP.NET MVC之三:Controller是如何解析出来的

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

    我们在上一篇文章中介绍Controller激活系统中所涉及到的一些类型,比如有关Controller类型的相关定义类型就包括了IController类型,IAsyncController类型,ControllerBase抽象类型和我们最终要使用的抽象类型Controller,这是ASP.NET MVC 框架中和Controller本身定义相关的类型。其他辅助类型,包括管理Controller的类型ControllerFactory,这个工厂负责Controller的生产和销毁。我们还涉及到另一个辅助类型,用于把系统默认定义的或者自定义的ControllerFactory注册到ASP.NET MVC框架中的类型ControllerBuilder。

     Controller类型、ControllerFactory类型和ControllerBuilder类型,他们之间的关系可以描述为:ControllerBuilder是面向客户的,或者说是程序员和ASP.NET MVC框架之间的桥梁。我们通过ControllerBuilder类型的SetControllerFactory方法把我们自定义的ControllerFactory类型实例注册到ASP.NET MVC框架中,ControllerFactory类型用于管理Controller类型实例,其实也就是说ControllerFactory类型就是ASP.NET MVC框架中的一个扩展点。

    我们今天主要讲Controller是怎么解析出来的,之所以把这一部分分开写,因为合在一起太长了,也说的不详细,如果大家对以上说的不太清楚,可以查看《白话ASP.NET MVC之二:Controller激活系统的概览》,  该文对ASP.NET MVC框架中所提到的Controlelr激活系统所涉及的类型有详细的介绍。

一、“路由系统”和“激活系统”是怎么关联起来的

     上一篇文章有过讲述,我们在这里简单说一下。ASP.NET 的路由系统是建立在一个叫做UrlRoutingModule的HttpModule组件上的,针对请求的路由解析是通过注册HttpApplication对象的PostResolveRequestCache事件来实现的,为当前的请求动态映射到一个HttpHandler类型上,最终由该HttpHandler接管请求并处理。我们来看看UrlRoutingModule类型的代码吧。

 1 [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
 2 public class UrlRoutingModule : IHttpModule
 3 {
 4     private static readonly object _contextKey = new object();
 5 
 6     private static readonly object _requestDataKey = new object();
 7 
 8     private RouteCollection _routeCollection;
 9 
10     public RouteCollection RouteCollection
11     {
12         get
13         {
14             if (this._routeCollection == null)
15             {
16                 this._routeCollection = RouteTable.Routes;
17             }
18             return this._routeCollection;
19         }
20         set
21         {
22             this._routeCollection = value;
23         }
24     }
25 
26     protected virtual void Dispose()
27     {
28     }
29 
30     protected virtual void Init(HttpApplication application)
31     {
32         if (application.Context.Items[UrlRoutingModule._contextKey] != null)
33         {
34             return;
35         }
36         application.Context.Items[UrlRoutingModule._contextKey] = UrlRoutingModule._contextKey;
37         application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
38     }
39 
40     private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
41     {
42         HttpContextBase context = new HttpContextWrapper(((HttpApplication)sender).Context);
43         this.PostResolveRequestCache(context);
44     }
45 
46     [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]
47     public virtual void PostMapRequestHandler(HttpContextBase context)
48     {
49     }
50 
51     public virtual void PostResolveRequestCache(HttpContextBase context)
52     {
53         RouteData routeData = this.RouteCollection.GetRouteData(context);
54         if (routeData == null)
55         {
56             return;
57         }
58         IRouteHandler routeHandler = routeData.RouteHandler;
59         if (routeHandler == null)
60         {
61             throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
62         }
63         if (routeHandler is StopRoutingHandler)
64         {
65             return;
66         }
67         RequestContext requestContext = new RequestContext(context, routeData);
68         context.Request.RequestContext = requestContext;
69         IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
70         if (httpHandler == null)
71         {
72             throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[]
73             {
74                 routeHandler.GetType()
75             }));
76         }
77         if (!(httpHandler is UrlAuthFailureHandler))
78         {
79             context.RemapHandler(httpHandler);
80             return;
81         }
82         if (FormsAuthenticationModule.FormsAuthRequired)
83         {
84             UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
85             return;
86         }
87         throw new HttpException(401, SR.GetString("Assess_Denied_Description3"));
88     }
89 
90     void IHttpModule.Dispose()
91     {
92         this.Dispose();
93     }
94 
95     void IHttpModule.Init(HttpApplication application)
96     {
97         this.Init(application);
98     }
99 }

  具体来说,该组件通过以RouteTable的静态属性Routes表示的路由表针对当前请求实施路由解析,如果有匹配,就会根据路由对象Route来生成RouteData路由数据对象,然后我们借助RouteData对象的RouteHandler属性获取想要的HttpHandler对象。在默认情况下这个RouteHandler属性所代表的对象是MvcRouteHandler。翠花,上代码:

 1 /// <summary>Creates an object that implements the IHttpHandler interface and passes the request context to it.</summary>
 2 public class MvcRouteHandler : IRouteHandler
 3 {
 4     private IControllerFactory _controllerFactory;
 5 
 6     /// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.MvcRouteHandler" /> class.</summary>
 7     public MvcRouteHandler()
 8     {
 9     }
10 
11     /// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.MvcRouteHandler" /> class using the specified factory controller object.</summary>
12     /// <param name="controllerFactory">The controller factory.</param>
13     public MvcRouteHandler(IControllerFactory controllerFactory)
14     {
15         this._controllerFactory = controllerFactory;
16     }
17 
18     /// <summary>Returns the HTTP handler by using the specified HTTP context.</summary>
19     /// <returns>The HTTP handler.</returns>
20     /// <param name="requestContext">The request context.</param>
21     protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
22     {
23             requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
24         return new MvcHandler(requestContext);
25     }
26 
27     /// <summary>Returns the session behavior.</summary>
28     /// <returns>The session behavior.</returns>
29     /// <param name="requestContext">The request context.</param>
30     protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
31     {
32         string text = (string)requestContext.RouteData.Values["controller"];
33         if (string.IsNullOrWhiteSpace(text))
34         {
35             throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);
36         }
37         IControllerFactory controllerFactory = this._controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
38         return controllerFactory.GetControllerSessionBehavior(requestContext, text);
39     }
40 
41     /// <summary>Returns the HTTP handler by using the specified request context.</summary>
42     /// <returns>The HTTP handler.</returns>
43     /// <param name="requestContext">The request context.</param>
44     IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
45     {
46         return this.GetHttpHandler(requestContext);
47     }
48 }

  在该类型里面包含了一个IControllerFactory类型成员字段,这个接口类型是所有ControllerFactory都要必须实现的接口,否则就不叫Controller的工厂了。MvcRouteHandler类型有两个构造函数,无参的没的说,另一个需要传递一个IControllerFactory类型的参数,这个参数用于初始化MvcRouteHandler类型内部包含的类型为IControllerFactory的_controllerFactory字段。当我们构造MvcRouteHandler实例的时候,如果我们调用了无参的构造函数,它会在内部使用ControllerBuilder.Current.GetControllerFactory()方法来获取我们通过ControllerBuilder类型注册的IControllerFactory类型的实例,代码很明显:

IControllerFactory controllerFactory = this._controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();

  MvcRouteHandler实现了IRouteHandler接口,目的只有一个,提供后续的HttpHandler,IRouteHandler接口定义如下:

public interface IRouteHandler
{
    IHttpHandler GetHttpHandler(RequestContext requestContext);
}

   MvcRouteHandler会给我们直接返回MvcHandler对象,这个对象用于处理请求,包括激活Controler对象,代码最有说服力,这份代码,上篇文章也贴过,现在也贴一下把,上代码:
  

  1    public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
  2     {
  3         private struct ProcessRequestState
  4         {
  5             internal IAsyncController AsyncController;
  6 
  7             internal IControllerFactory Factory;
  8 
  9             internal RequestContext RequestContext;
 10 
 11             internal void ReleaseController()
 12             {
 13                 this.Factory.ReleaseController(this.AsyncController);
 14             }
 15         }
 16 
 17         private static readonly object _processRequestTag = new object();
 18 
 19         internal static readonly string MvcVersion = MvcHandler.GetMvcVersionString();
 20 
 21         /// <summary>Contains the header name of the ASP.NET MVC version.</summary>
 22         public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";
 23 
 24         private ControllerBuilder _controllerBuilder;
 25 
 26         internal ControllerBuilder ControllerBuilder
 27         {
 28             get
 29             {
 30                 if (this._controllerBuilder == null)
 31                 {
 32                     this._controllerBuilder = ControllerBuilder.Current;
 33                 }
 34                 return this._controllerBuilder;
 35             }
 36             set
 37             {
 38                 this._controllerBuilder = value;
 39             }
 40         }
 41 
 42         /// <summary>Gets or sets a value that indicates whether the MVC response header is disabled.</summary>
 43         /// <returns>true if the MVC response header is disabled; otherwise, false.</returns>
 44         public static bool DisableMvcResponseHeader
 45         {
 46             get;
 47             set;
 48         }
 49 
 50         /// <summary>Gets a value that indicates whether another request can use the <see cref="T:System.Web.IHttpHandler" /> instance.</summary>
 51         /// <returns>true if the <see cref="T:System.Web.IHttpHandler" /> instance is reusable; otherwise, false.</returns>
 52         protected virtual bool IsReusable
 53         {
 54             get
 55             {
 56                 return false;
 57             }
 58         }
 59 
 60         /// <summary>Gets the request context.</summary>
 61         /// <returns>The request context.</returns>
 62         public RequestContext RequestContext
 63         {
 64             get;
 65             private set;
 66         }
 67 
 68         /// <summary>Gets a value that indicates whether another request can use the <see cref="T:System.Web.IHttpHandler" /> instance.</summary>
 69         /// <returns>true if the <see cref="T:System.Web.IHttpHandler" /> instance is reusable; otherwise, false.</returns>
 70         bool IHttpHandler.IsReusable
 71         {
 72             get
 73             {
 74                 return this.IsReusable;
 75             }
 76         }
 77 
 78         /// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.MvcHandler" /> class.</summary>
 79         /// <param name="requestContext">The request context.</param>
 80         /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestContext" /> parameter is null.</exception>
 81         public MvcHandler(RequestContext requestContext)
 82         {
 83             if (requestContext == null)
 84             {
 85                 throw new ArgumentNullException("requestContext");
 86             }
 87             this.RequestContext = requestContext;
 88         }
 89 
 90         /// <summary>Adds the version header by using the specified HTTP context.</summary>
 91         /// <param name="httpContext">The HTTP context.</param>
 92         protected internal virtual void AddVersionHeader(HttpContextBase httpContext)
 93         {
 94             if (!MvcHandler.DisableMvcResponseHeader)
 95             {
 96                 httpContext.Response.AppendHeader(MvcHandler.MvcVersionHeaderName, MvcHandler.MvcVersion);
 97             }
 98         }
 99 
100         /// <summary>Called by ASP.NET to begin asynchronous request processing.</summary>
101         /// <returns>The status of the asynchronous call.</returns>
102         /// <param name="httpContext">The HTTP context.</param>
103         /// <param name="callback">The asynchronous callback method.</param>
104         /// <param name="state">The state of the asynchronous object.</param>
105         protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
106         {
107             HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
108             return this.BeginProcessRequest(httpContext2, callback, state);
109         }
110 
111         /// <summary>Called by ASP.NET to begin asynchronous request processing using the base HTTP context.</summary>
112         /// <returns>The status of the asynchronous call.</returns>
113         /// <param name="httpContext">The HTTP context.</param>
114         /// <param name="callback">The asynchronous callback method.</param>
115         /// <param name="state">The state of the asynchronous object.</param>
116         protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
117         {
118             IController controller;
119             IControllerFactory factory;
120             this.ProcessRequestInit(httpContext, out controller, out factory);
121             IAsyncController asyncController = controller as IAsyncController;
122             if (asyncController != null)
123             {
124                 BeginInvokeDelegate<MvcHandler.ProcessRequestState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, MvcHandler.ProcessRequestState innerState)
125                 {
126                     IAsyncResult result;
127                     try
128                     {
129                         result = innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState);
130                     }
131                     catch
132                     {
133                         innerState.ReleaseController();
134                         throw;
135                     }
136                     return result;
137                 };
138                 EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> endDelegate = delegate(IAsyncResult asyncResult, MvcHandler.ProcessRequestState innerState)
139                 {
140                     try
141                     {
142                         innerState.AsyncController.EndExecute(asyncResult);
143                     }
144                     finally
145                     {
146                         innerState.ReleaseController();
147                     }
148                 };
149                 MvcHandler.ProcessRequestState invokeState = new MvcHandler.ProcessRequestState
150                 {
151                     AsyncController = asyncController,
152                     Factory = factory,
153                     RequestContext = this.RequestContext
154                 };
155                 SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext();
156                 return AsyncResultWrapper.Begin<MvcHandler.ProcessRequestState>(callback, state, beginDelegate, endDelegate, invokeState, MvcHandler._processRequestTag, -1, synchronizationContext);
157             }
158             Action action = delegate
159             {
160                 try
161                 {
162                     controller.Execute(this.RequestContext);
163                 }
164                 finally
165                 {
166                     factory.ReleaseController(controller);
167                 }
168             };
169             return AsyncResultWrapper.BeginSynchronous(callback, state, action, MvcHandler._processRequestTag);
170         }
171 
172         /// <summary>Called by ASP.NET when asynchronous request processing has ended.</summary>
173         /// <param name="asyncResult">The asynchronous result.</param>
174         protected internal virtual void EndProcessRequest(IAsyncResult asyncResult)
175         {
176             AsyncResultWrapper.End(asyncResult, MvcHandler._processRequestTag);
177         }
178 
179         private 
                      

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
ASP.NET Core - 实现自定义WebApi模型验证 ModelState发布时间:2022-07-10
下一篇:
asp.net六大对象之Request、Response发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap