一、前言
對(duì)于WebForm開發(fā),請(qǐng)求通常是一個(gè)以.aspx結(jié)尾的url,對(duì)應(yīng)一個(gè)物理文件,從代碼的角度來說它其實(shí)是一個(gè)控件(Page)。而在MVC中,一個(gè)請(qǐng)求對(duì)應(yīng)的是一個(gè)Controller里的Action。熟悉asp.net的朋友都知道,asp.net請(qǐng)求實(shí)際都是交給HttpHandler處理(實(shí)現(xiàn)了IHttpHandler的類型)。無論是.aspx,.ashx,.asmx 還是MVC里的Action,請(qǐng)求都會(huì)交給HttpHandler。具體是在管道事件中,會(huì)根據(jù)請(qǐng)求創(chuàng)建一個(gè)HttpHandler,并執(zhí)行它的PR方法。對(duì)于aspx和ashx都很好理解,因?yàn)樗鼈儽旧砭蛯?shí)現(xiàn)了IHttpHandler接口,而MVC的Controller和Action都和HttpHandler沒有關(guān)系,它是如何實(shí)現(xiàn)的呢?接下來我們就看一個(gè)請(qǐng)求是如何進(jìn)入mvc框架內(nèi)部的。
二、例子
WebForm和MVC都是建立在asp.net平臺(tái)上的,Webform出現(xiàn)得比較早,那么MVC是如何做到在不影響底層框架,實(shí)現(xiàn)擴(kuò)展的呢?這主要得益于asp.net的路由機(jī)制。路由機(jī)制并不屬于MVC,WebForm也可以使用它。它的目的是讓一個(gè)請(qǐng)求與物理文件分離,原理是通過映射關(guān)系,將請(qǐng)求映射到指定的HttpHandler。例如我們也可以將一個(gè)/Admin/User.aspx?name=張三 的請(qǐng)求映射成可讀性更好的/Admin/張三。下面是兩種url的注冊(cè)方式:
public static void RegisterRoutes(RouteCollection routes){ //MVC routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); //WebForm routes.MapPageRoute( routeName: "WebForm", routeUrl: "Admin/{user}", physicalFile: "~/Admin/User.aspx" );}
RouteCollection是一個(gè)Route集合,Route封裝了名稱、url模式、約束條件、默認(rèn)值等路由相關(guān)信息。其中,MapPageRoute是RouteCollection定義的方法,而MapRoute是MVC擴(kuò)展出來的(擴(kuò)展方法的好處就是可以在不修改原有代碼的情況下添加所需的功能)。它們的目的都是一樣的,創(chuàng)建一個(gè)Route對(duì)象,添加到集合當(dāng)中;我們也可以new 一個(gè)Route對(duì)象,然后調(diào)用RouteCollection.Add,效果是一樣的。下面我們主要關(guān)注MVC的實(shí)現(xiàn)過程,WebForm其實(shí)也是類似的。
三、分析源碼
接下來我們看MVC是如何利用路由機(jī)制實(shí)現(xiàn)擴(kuò)展的。路由機(jī)制是通過一個(gè)UrlRoutingModule完成的,它是一個(gè)實(shí)現(xiàn)了IHttpModule的類,路由模塊已經(jīng)默認(rèn)幫我們注冊(cè)好了。HttpModule通過注冊(cè)HttpApplication事件參與到管道處理請(qǐng)求中,具體是訂閱HttpApplication某個(gè)階段的事件。路由機(jī)制就是利用這個(gè)原理,UrlRoutingModule訂閱了PostResolveRequestCache 事件,實(shí)現(xiàn)url的映射。為什么是該事件呢?因?yàn)樵撌录南乱徊骄鸵瓿烧?qǐng)求和物理文件的映射,所以必須要此之前進(jìn)行攔截。核心代碼如下:
public class UrlRoutingModule : IHttpModule { public RouteCollection RouteCollection { get { if (_routeCollection == null) { //全局的RouteCollection集合 _routeCollection = RouteTable.Routes; } return _routeCollection; } set { _routeCollection = value; } } protected virtual void Init(HttpApplication application) { //注冊(cè)PostResolveRequestCache事件 application.PostResolveRequestCache += OnApplicationPostResolveRequestCache; } private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { //創(chuàng)建上下文 HttpApplication app = (HttpApplication)sender; HttpContextBase context = new HttpContextWrapper(app.Context); PostResolveRequestCache(context); } public virtual void PostResolveRequestCache(HttpContextBase context) { //1.獲取RouteData RouteData routeData = RouteCollection.GetRouteData(context); if (routeData == null) { return; } //2.獲取IRouteHandler IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { } //RequestContext保證了HttpContext和RouteData,在后續(xù)使用 RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; //3.獲取IHttpHandler IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); //重新映射到處理程序 context.RemapHandler(httpHandler); }}
新聞熱點(diǎn)
疑難解答
圖片精選