天天看點

一起談.NET技術,ASP.NET Routing對請求的處理方式

  原本這是《關于ASP.NET Routing的幾點内容》一文中的一節,不過等寫完這節之後發現這塊内容已經比較完整了,而且它本身也是獨立和最為常見的部分,是以我把它提取出來單獨成文。至于那片文章的其他部分我會再修改一下,明天釋出。希望這些内容會對您了解ASP.NET Routing工作方式,以及閱讀ASP.NET Routing的代碼有所幫助。

  首先,如果您需要在項目中使用在ASP.NET Routing的功能,則需要在web.config檔案中配置一個HttpModule:

<add name="UrlRoutingModule"

 type="System.Web.Routing.UrlRoutingModule, System.Web.Routing,..." />

  其次,您應該在Application_Start中向RouteCollection類型的RouteTable.Routes集合中添加一系列RouteBase對象,并為每個RouteBase對象指定一個獨立的名稱(大小寫無關)。當然,您也可以在運作時動态添加或删除内容(RouteCollection對象是線程安全的),隻不過我們平時不太會去這麼做而已。值得注意的是,RouteCollections裡的RouteBase對象,它們的順序是非常重要的。

  UrlRouteModule會監聽ASP.NET Request Pipelines的PostResolveRequestCache事件,在這個事件中UrlRouteModule會将目前的HttpContext作為參數調用RouteTable.Routes集合的GetRouteData方法。在RouteCollection的GetRouteData方法中,又會依次将HttpContext傳入每一個RouteBase對象的GetRouteData方法,如果中途某個RouteBase對象傳回了一個非null的結果,則這個結果便會直接傳回給UrlRouteModule。

  如果UrlRouteModule調用RouteTable.Routes.GetRouteData方法得到了null,則“一切都像沒有發生過”。如果GetRouteData方法得到了結果——一個RouteData對象,此時RouteData.Values便會包含請求中捕獲到的資料。RouteData中另一個重要的成員便是RouteData.RouteHandler屬性,它傳回一個IRouteHandler對象。IRouteHandler接口中隻有一個方法GetHttpHandler,它接受RequestContext作為參數,并傳回一個IHttpHandler對象。如ASP.NET MVC架構在利用  ASP.NET Routing時,便會使用MvcRouteHandler來傳回一個MvcHandler對象。

  不過,UrlRouteModule在得到了IRouteHandler對象之後,并不會直接調用其GetHttpHandler方法,而是判斷它是不是ASP.NET Routing自帶的StopRoutingHandler類型。StopRoutingHandler是個特殊的IRouteHandler對象,它的作用隻是告訴UrlRouteModule,雖然某個規則比對成功了,但是——也還是當什麼都沒發生過吧。是以,如果我們想要“跳過”一些形式的請求,往往則需要将“忽略”功能放在其他所有規則之前。如:

public static void RegisterRoutes(RouteCollection routes)

{

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.IgnoreRoute("scripts/{*pathInfo}");

routes.IgnoreRoute("images/{*pathInfo}");

routes.MapRoute(

"Default", // Route name

"{controller}/{action}/{id}", // URL with parameters

new { controller = "Home", action = "Index", id = "" } // Parameter defaults

);

}

  IgnoreRoute是定義在ASP.NET MVC中,基于RouteCollection類型的擴充方法。它會向RouteCollection中添加一個Route對象,而這個Route對象在比對成功時傳回的RouteData對象,其RouteHandler屬性便為一個StopRoutingHandler,于是餘下的Routing規則也不會繼續比對了——這一點和RouteBase對象傳回null不同,因為如果傳回null,則餘下的規則還會依次比對。如果傳回了一個包含StopRoutingHander的RouteData,則剩下的Routing規則全部跳過。

  如果UrlRouteModule得到的IRouteHandler對象不是StopRoutingHandler,則便會通過其GetHttpHandler方法獲得那個IHttpHandler對象。這個IHttpHandler對象會被放入HttpContext的Items集合中。至此,Request Pipeline的PostResolveRequestCache事件便結束了。

  UrlRouteModule還會監聽PostMapRequest事件,此時Module便會查找HttpContext.Items集合的特定位置中是否包含一個IHttpHandler對象,如果存在,則會将這個對象設為目前HttpContext對象的Handler屬性的值。于是當ASP.NET繼續執行下去時,便會調用這個Handler的ProcessRequest方法來處理請求了。

  如果這個IHttpHandler對象是MvcHttpHandler,那麼它便會從RouteData中擷取一些資料,構造Controller對象,執行Action等等。如果它是一個DynamicDataHandler,或是WebForm的HttpHandler,那麼剩下的便是各自的模型的處理方式了。

  是以,ASP.NET Routing是一個通用的元件,它不涉及到任何具體的請求處理方式。如果您需要,也可以自己基于它進行開發——如FubuMvc項目就是這麼做的。

繼續閱讀