自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

ASP.NET Routing之“解析URL”功能詳解

開發(fā) 后端
ASP.NET Routing中的“解析URL”功能可以把一個字符串根據(jù)指定的Pattern拆分成鍵/值對。本文介紹這個功能的簡易實現(xiàn)方法。

經常看我博客的人可能會知道,我是一個喜歡搞點小技巧來實現(xiàn)某個功能的人。例如博客的皮膚,自己花了不少時間定義,也是為了效果豐富一些。當然,搞得最多的是從框架或類庫內部取出一點小功能來用用,節(jié)省自己開發(fā)的時間。這其實也是一種復用,尤其是開發(fā)一些“擴展”的時候,例如當時嘗試為UpdatePanel增加上傳功能,雖然最后的結果不是很理想,但是大部分的Hack以及前后端的交互是非常成功的(最大的問題在于跨瀏覽器實現(xiàn)iframe通信)。而現(xiàn)在也打算總結一次這方面的簡單技巧,為以后的文章貢獻點引用資源。

ASP.NET Routing中解析URL功能介紹與實現(xiàn)

這次我們想“復用”的內容是ASP.NET URL Routing中“解析URL”的功能。具體一點地說,就是把一個字符串根據(jù)指定的Pattern拆分成鍵/值對的功能。從.NET Reflector反編譯System.Web.Routing.dll的結果來看,這部分的解析工作是交由RouteParser和ParsedRoute兩個類完成的。這里引用一下相關的使用代碼,如果您感興趣的話,也可以閱讀它們完整的實現(xiàn):

  1. public class Route  
  2. {  
  3.     public string Url  
  4.     {  
  5.         get { ... }  
  6.         set 
  7.         {  
  8.             this._parsedRoute = RouteParser.Parse(value);  
  9.             this._url = value;  
  10.         }  
  11.     }  
  12.  
  13.     public override RouteData GetRouteData(HttpContextBase httpContext)  
  14.     {  
  15.         string virtualPath = ...  
  16.         RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);  
  17.  
  18.         ...  
  19.     }  
  20.  
  21.     ...  
  22. }  

從代碼中可以看出,RouteParser的作用是將一個Pattern(如"{controller}/{action}/{id}")轉化成一個“解析器”,而這個解析器便是ParsedRoute類。在需要拆分一個URL字符串(如"Home/Index/5")的時候,便會調用ParsedRoute類的Match方法,由此得到一個RouteValueDictionary對象,其中包含了Pattern中定義的名稱,和一些值的映射關系。

可能您也能夠輕易實現(xiàn)這樣的功能,不過既然微軟已經幫我們做好了,我們也不妨直接使用一下,偶爾用來拆拆字符串也是挺方便的。只可惜RouteParser和ParsedRoute都是由internal修飾的,我們無法直接訪問到。那么就用點小技巧吧……說實話,其實您會發(fā)現(xiàn)也就這么一回事,“反射”罷了。因此,我們便學著ASP.NET Routing的做法,構建兩個類吧:

解析URL的兩個類

  1. internal static class RouteParser  
  2. {  
  3.     public static ParsedRoute Parse(string routeUrl) { ... }  
  4. }  
  5.  
  6. internal class ParsedRoute  
  7. {  
  8.     public RouteValueDictionary Match(string virtualPath, RouteValueDictionary defaultValues) { ... }  
  9. }  
  10.  

我們目前的做法算是一種Hack,為了保證其可維護性,我會選擇與目標類庫/框架的接口盡可能完全一致的做法。這么做的好處在于,我可以很輕易地理解正在實現(xiàn)的功能,一旦出現(xiàn)了任何問題,就可以直接去找對應的內部實現(xiàn),而不用在一堆堆的反射關系中“翱翔”。

接著便可以實現(xiàn)我們需要的效果了。在這里,我使用了FastReflectionLib來加快反射調用的性能。雖然我不是一個追求性能極致的Geek,但是如果有一種幾乎不耗費額外代價,就能得到數(shù)百倍的性能提升,何樂而不為呢?

  1. internal static class RouteParser  
  2. {  
  3.     private static MethodInvoker s_parseInvoker;  
  4.  
  5.     static RouteParser()  
  6.     {  
  7.         var parserType = typeof(Route).Assembly.GetType("System.Web.Routing.RouteParser");  
  8.         var parseMethod = parserType.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public);  
  9.         s_parseInvoker = new MethodInvoker(parseMethod);  
  10.     }  
  11.  
  12.     public static ParsedRoute Parse(string routeUrl)  
  13.     {   
  14.         return new ParsedRoute(s_parseInvoker.Invoke(null, routeUrl));  
  15.     }  
  16. }  
  17.  
  18. internal class ParsedRoute  
  19. {  
  20.     private static MethodInvoker s_matchInvoker;  
  21.  
  22.     static ParsedRoute()  
  23.     {  
  24.         var routeType = typeof(Route).Assembly.GetType("System.Web.Routing.ParsedRoute");  
  25.         var matchMethod = routeType.GetMethod("Match", BindingFlags.Instance | BindingFlags.Public);  
  26.         s_matchInvoker = new MethodInvoker(matchMethod);  
  27.     }  
  28.  
  29.     private object m_instance;  
  30.  
  31.     public ParsedRoute(object instance)  
  32.     {  
  33.         this.m_instance = instance;  
  34.     }  
  35.  
  36.     public RouteValueDictionary Match(string virtualPath, RouteValueDictionary defaultValues)  
  37.     {  
  38.         return (RouteValueDictionary)s_matchInvoker.Invoke(this.m_instance, virtualPath, defaultValues);  
  39.     }  
  40. }  

兩個類其實都是使用反射,從類庫中獲取合適的MethodInfo,然后交給MethodInvoker去執(zhí)行。其他的……由于代碼過于簡單,我都不知道還需要解釋什么東西。最后就使用xUnit測試一下吧:

解析URL效果測試

  1. public class ParseRouteTest  
  2. {  
  3.     [Fact]  
  4.     public void Basic_Parsing()  
  5.     {  
  6.         var parsedRoute = RouteParser.Parse("{controller}/{action}/{id}");  
  7.         var values = parsedRoute.Match("Home/Index/5"null);  
  8.         Assert.Equal("Home", values["controller"]);  
  9.         Assert.Equal("Index", values["action"]);  
  10.         Assert.Equal("5", values["id"]);  
  11.     }  
  12. }  

說實話,這個方法并沒有太多技術含量,由于我們將自己的實現(xiàn)和目標實現(xiàn)完全對應起來,所以我們所要做的,似乎也都是些機械的“映射”功能而已。這就引發(fā)了我的一個想法,既然很“機械”,那么為什么不去讓它“自動”完成呢?例如,我們完全可以寫一個類庫,來實現(xiàn)這樣的效果:

  1. [Type("System.Web.Routing.ParsedRoute, ...")]  
  2. interface IParsedRoute  
  3. {  
  4.     RouteValueDictionary Match(string virtualPath, RouteValueDictionary defaultValues);  
  5. }  
  6.  
  7. [Type("System.Web.Routing.RouteParser, ...")]  
  8. interface IRouteParser  
  9. {  
  10.     [Static]  
  11.     IParsedRoute Parse(string url);  
  12. }  

通過定義接口和標記,我們可以直接“聲明”需要“挖掘”出來的類型是什么。然后自然可以有框架為我們進行匹配:

  1. IRouteParser parser = HackFactory.Create<IRouteParser>();  
  2. IParsedRoute route = parser.Parse("{controller}/{action}/{id}");  
  3. RouteValueDictionary values = route.Match("Home/Index/5"null); 

是不是一下子變得爽快了許多?簡單想了想,這樣的框架從技術上來說似乎并沒有太多困難。

以上就對ASP.NET Routing中的“解析URL”功能進行了介紹。本文來自老趙點滴:《復用類庫內部已有功能》

【編輯推薦】

  1. 為ASP.NET MVC應用添加自定義路由
  2. 學習ASP.NET MVC路由的使用方法
  3. 淺析ASP.NET中的URL Rewrite
  4. 淺談ASP.NET MVC框架
  5. 介紹ASP.NET MVC中的MvcAjaxPanel
責任編輯:yangsai 來源: 老趙點滴
相關推薦

2009-10-26 15:55:43

URL Routing

2009-08-19 09:23:40

ASP.NET Rou

2009-07-21 15:11:14

ASP.NET Rou

2009-07-22 18:08:00

ASP.NET跨頁提交

2009-07-28 17:17:19

ASP.NET概述

2009-07-29 16:08:07

ASP和ASP.NET

2009-07-31 09:39:59

ASP.NET和URL

2009-08-05 13:16:43

ASP.NET URL

2009-08-05 14:46:17

ASP.NET url

2009-03-12 10:42:38

RoutingIgnoreRouteASP.NET

2014-08-26 09:22:40

ASP.NET MVCRouting

2009-07-28 16:57:50

ASP.NET Ses

2009-07-24 10:14:22

ASP.NET開發(fā)

2009-08-05 11:14:33

ASP.NET ISA

2009-07-22 16:25:41

ASP.NET AJA

2009-07-23 13:19:51

2009-03-09 13:46:31

RoutingWebASP.NET

2009-08-05 10:17:55

ASP.NET TheASP.NET開發(fā)技巧

2009-07-27 17:26:39

ASP.NET功能

2009-08-10 13:32:15

ASP.NET TimASP.NET組件設計
點贊
收藏

51CTO技術棧公眾號