ASP.NET MVC 開發心得分享 (21):Routing 觀念與技巧
ASP.NET MVC 預設在 Global.asax 所定義的 RegisterRoutes 方法中可以輕易的定義你希望擁有的網址格式,嚴格上來講這並非 ASP.NET MVC 的專利,而是從 ASP.NET 3.5 SP1 就加入的新特性,所以就算是傳統的 ASP.NET Web Form 一樣可以利用 Routing 所帶來的好處,今天我就來講一些 Routing 的觀念與技巧。
快速上手
我先解釋在 ASP.NET MVC 專案中 Global.asax 所定義的 Routing 程式碼,這也是初學者很容易看不懂的地方。
以下文字用來描述上圖標號的部分:
- ASP.NET 執行的起點就在於 HttpApplication 的 Application_Start() 方法,所有 Routing 都會定義在此,其中 RouteTable.Routes 是一個公開的靜態物件,用來儲存所有的 Routing 規則,其物件型別為 RouteCollection。
- 在預設 RegisterRoutes 方法中的 IgnoreRoute 用來定義 不要透過 Routing 處理的網址。
註: IgnoreRoute 擴充方法是 ASP.NET MVC (System.Web.Mvc) 的一部份。 - {resource} 代表一個 路由變數(RouteValue),其名稱為 resource,但在這裡其實取任何名字都可以,這裡只代表一個變數空間 (PlaceHolder) 罷了。總之就是代表一個「位置」,可以放入一個用不到的變數。
- {*pathInfo} 也是代表一個 RouteValue 名稱為 pathInfo,但名稱前面的星號 ( * ) 代表 CatchAll的意思,這個名為 pathInfo 的 RouteValue 會是完整的 PATH INFO 扣除 標號 3 比對到的網址。例如:若網址是 /TEST.axd/a/b/c/d 則 pathInfo 所得到的值為 a/b/c/d,如果沒加上星號 ( * ) 該 pathInfo 就會等於 a 而已。而在這裡其實取任何名字都可以,這裡也只是代表一個變數的位置。
- MapRoute 則是最常用來定義 Routing 規則的擴充方法。
註: MapRoute 擴充方法是 ASP.NET MVC (System.Web.Mvc) 的一部份。 - 定義 Route 名稱,這個名稱雖然少用,但是開發到較為進階的 Routing 技巧時會用到。
- 定義 網址格式 與每個 網址段落(Path Segment) 的 RouteValue 參數名稱。
注意: 該網址不能以斜線 ( / ) 開頭。 - 定義各 RouteValue 參數的預設值
基本觀念
- Routing (System.Web.Routing) 是 ASP.NET 3.5 SP1 的一部份,ASP.NET MVC 只是使用而已
- RouteTable.Routes 是一個公開的靜態物件,在整個 HttpApplication 生命週期裡都會固定存在!
- 由於 RouteTable.Routes 是一個公開的靜態物件,所以在不用重新編譯網站的情況下是有可能動態調整 RouteTable.Routes 內容的。詳見:Editable Routes 與 Editable Routes Using App_Code
- IgnoreRoute 與 MapRoute 這兩個擴充方法 (ExtensionMethod) 是 System.Web.Mvc 命名空間中所新增的 RouteCollectionExtensions 類別所提供的擴充方法,為了方便撰寫 Routing 規則之用。
- 在 Routing 規則集之中,第一個被比對成功的規則就會直接被採用,此原則跟 Firewall Rules 類似
路由開發技巧
技巧 1:替 Routing 網址設立條件限制
由於 ASP.NET MVC 有個很重要的特性:以習慣取代設定 (Convention over Configuration),所以當我們從網址路徑對應到 Controller 的過程中,網址列上的路由變數會自動對應到 Action 方法的參數中,例如我們在 Global.asax.cs 檔案中有以下路由定義:
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"}
);
而我們的 Action 方法的內容如下:
public ActionResult Details(int productId)
{
return View();
}
因為我們 Action 方法裡的參數是 int 型別,所以傳入的 productId 路由變數必須要是「整數」,如果不是整數的話,就會導致 The parameters dictionary contains a null entry for parameter 'productId' of non-nullable type 'System.Int32' for method 'System.Web.ActionResult Details(Int32)' in ... 的錯誤發生。
要避免這種無效的網址路由比對,我們可以在定義路由時多下一些限制條件,來進一步比對 網址段落(PathSegment) 是否符合 路由變數(RouteValue) 的格式要求,我們以上述例子來進一步修改路由定義,如下程式範例,我們多增加了一個參數傳入 MapRoute 參數,其中 \d+ 是 正規表示式(RegEx) 樣式:
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"},
new {productId = @"\d+" }
);
注意:這裡的 RegEx 樣式在比對時會自動幫你加上 ^ 開頭與 $ 結尾,也代表這個樣式一定會比對完整的 網址段落(Path Segment)。
如此一來,當網址輸入的格式是 /Product/CellPhone 的時候,就不會比對到 "Product" 這一條路由規則。
技巧 2:自訂 Routing 條件限制
一般情況下透過 RegEx 正規表示式來定義 RouteValue 條件限制已經很足夠,但若遇到需要較為複雜的判斷情況時,就有可能要自訂 Routing 條件限制,自訂的方法是透過實做 IRouteConstraint 介面的方式來完成,該介面只有一個 Match 方法需要實做,以下是該方法的定義:
bool Match(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
有了這些傳入的參數,你將可以取得許多在網址變數比對時可能得到的各種資訊,再拿這些取得的資料進行判斷,就可以有成千上百種條件的限制組合,任你怎樣寫都可以。例如你想設定一組只有在 Localhost 本機執行網站時才能使用的路由限制(Route Constraint),我們可以透過 httpContext.Request.IsLocal 判斷來源電腦是否來自於本機,這樣我們可以寫出以下程式碼:
using System.Web;
using System.Web.Routing;
namespace MvcApplication1.Constraints {
public class LocalhostConstraint : IRouteConstraint {
public bool Match (HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
return httpContext.Request.IsLocal;
}
}
}
那麼我們在 Global.asax.cs 裡的路由規則又應該如何定義呢?請看以下程式碼:
routes.MapRoute(
"Admin",
"Admin/{action}",
new { controller="Admin" },
new { isLocal=new LocalhostConstraint() }
);
眼尖的人可能會發現我們在限制條件的地方使用了一個 isLocal 變數,但是該變數根本沒有出現在網址格式 之中出現過,但為什麼能用呢?這是要限制誰呢?真的有一個 isLocal 這個 RouteValue 變數嗎?
我相信初學者看到這些程式碼很可能會有這些疑問,因為當時的我看到這段 Code 也質疑了一下,事實上自訂路由限制套用在路由定義時,其匿名變數的屬性名稱一點也不重要,所有的判斷都是寫在自訂路由限制的程式碼裡,所以上述的路由定義如果我修改成以下,還是可以正常運作的,你自己取名的時候只要自己覺得好記、好懂即可:
routes.MapRoute(
"Admin",
"Admin/{action}",
new { controller="Admin" },
new { OnlyLocalhostCanApply=new LocalhostConstraint() }
);
技巧 3:讓 ASP.NET MVC 與 ASP.NET Web Form 和平共處
基於 ASP.NET MVC 與 ASP.NET Web Form 的運作方式不同,所以通常這兩種架構下的程式在預設的情況下都能正常的運作,只有在某些特殊的設定下才會兩邊互相干擾,當你網站部署時遇到互相干擾的狀況時,就可以套用以下 Routing 技巧,設定特定一些路徑不要走 ASP.NET MVC 的執行管線。
以下是一些過濾掉路由規則定義的程式碼範例:
- 忽略所有 *.aspx 的網址路徑
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
- 忽略所有在 Page 目錄下的所有程式與檔案 ( 請注意,這是忽略 Routing 而已,改由 IIS 來判斷要用何種 Handler 來處理這次 HTTP 要求 )
routes.IgnoreRoute("Page/{*pathInfo}");
- 忽略所有在 Page 目錄下的所有檔案 ( 另一種寫法 )
routes.Add(new Route("Page/{*pathInfo}", new StopRoutingHandler()));
另外還有一點也值得注意,也就是 Routing 的動作其實是在執行 HttpHandler 執行之前,他是一個專門用來分配 Request 的模組,所以可以透過 Routing 的定義與設定來決定到底後續要執行 ASP.NET MVC 還是 ASP.NET Web Form,在 IIS7 的 HTTP Request 的執行順序中,UrlRoutingModule (Routing module) 的執行順位如下圖示,執行事件名稱為 Resolve Cache 這一步之後(PostResolveRequestCache):
以下一些參考連結可以幫助你學習如何讓 ASP.NET Web Form 的網頁也套用 Routing 規則:
- Using Routing With WebForms
- URL Routing with ASP.NET 4 Web Forms (VS 2010 and .NET 4.0 Series)
- Extreme ASP.NET - Routing with ASP.NET Web Forms
技巧 4:讓 Routing 也對已存在的檔案做處理 (將所有網址都透過 Routing 進行比對)
當 HTTP 要求進來後,在 ASP.NET Routing 在預設的情況下,只要當輸入的網址路徑可以比對出在實體的檔案系統中的檔案,就會直接跳過 Routing 機制,這也是為什麼 ASP.NET MVC 與 ASP.NET Web Form 可以和平共處的原因之一,因為 ASP.NET Web Form 一定會有個 aspx 檔案 (或其他檔案類型),當 HTTP 要求進來後,就會立即找到有個實體檔案在,這時就會直接跳過 ASP.NET Routing 機制。
這樣的設計其實在大部分的環境下都可以正常運作,但在一些特殊的設計裡,你可能會想要求所有 HTTP 要求都必須經過 ASP.NET Routing 機制的比對才行 (例如你想藉由 ASP.NET Routing 實做權限管理),這時就可以在 Global.asax.cs 檔案裡的 RegisterRoutes 方法加上以下程式碼即可:
routes.RouteExistingFiles = true;
如下圖示:
這樣的設計當然也會帶來一些副作用,因為當你真的有實體檔案要能直接透過 IIS 回應的時候,就必須針對特定的檔案類型或路徑設定 IgnoreRoute 或 StopRoutingHandler (本文技巧 3 有提到)。
ASP.NET MVC 開發心得分享 (21):Routing 觀念與技巧的更多相关文章
- Delphi APP 開發入門(九)拍照與分享
Delphi APP 開發入門(九)拍照與分享 分享: Share on facebookShare on twitterShare on google_plusone_share 閲讀次數:30 ...
- ASP.NET MVC TempData使用心得
说明: 在ASP.NET MVC中資料傳遞主要有ViewData與TempData ViewData主要是Controller傳遞Data給View,存留期只有一個Action,要跨Action要使用 ...
- Delphi APP 開發入門(七)通知與雲端推播
Delphi APP 開發入門(七)通知與雲端推播 分享: Share on facebookShare on twitterShare on google_plusone_share 閲讀次數: ...
- 自己用的一个ASP.Net MVC分页拿出来分享下(转)
实例懒得做.切几个图把代码发上要用的自己搞啦~ 下面是一个helper类. namespace System.Web.Mvc { public enum BarStyle { yahoo, digg, ...
- [ASP.NET MVC 小牛之路]07 - URL Routing
我们知道在ASP.NET Web Forms中,一个URL请求往往对应一个aspx页面,一个aspx页面就是一个物理文件,它包含对请求的处理. 而在ASP.NET MVC中,一个URL请求是由对应的一 ...
- ASP.NET MVC 小牛之旅3:Routing——网址路由
网址路由(Routing)在ASP.NET MVC中有两个主要用途,一个用途是匹配通过浏览器传来的HTTP请求,另一个用途则是响应适当的网址给浏览器. 3.1匹配通过浏览器传来的HTTP请求 首先我们 ...
- IIS 发布ASP.NET MVC 4.0 错误500.21解决办法
由VS2013 写好的MVC 4.0 发布在服务器IIS 上报错500.21,解决办法:尝试多种网上介绍的办法,最后发现还是模块问题.
- 【ASP.NET MVC 学习笔记】- 08 URL Routing
本文参考:http://www.cnblogs.com/willick/p/3343105.html 1.URL Routing告诉MVC如何正确的定位Controller和Action. 2.URL ...
- ASP.NET MVC5写.php路由匹配时的问题 ASP.NET MVC 4 在 .NET 4.0 与.NET 4.5 的專案範本差異
由于外包公司结束合作,所以考虑把其APP服务替换过来,因原后台是用php写的,在不影响员客户端使用的情况下在MVC下重写路由配置实现处理原php链接地址的请求,但实现时发现怎么也匹配不到自己写的路由, ...
随机推荐
- php 加密解密方法
<?php//可用于加密解密,如cookie,账号,手机号 as so on class DES { var $key; var $iv; //偏移量 function __construct( ...
- WPF中三种方法得到当前屏幕的宽和高
WPF程序中的单位是与设备无关的单位,每个单位是1/96英寸,如果电脑的DPI设置为96(每个英寸96个像素),那么此时每个WPF单位对应一个像素,不过如果电脑的DPI设备为120(每个英寸120个像 ...
- Silverlight之我见
好长时间没搞Silverlight方面的开发了,原本都以为自己早已忘记,然而前阵子(确切一点说,是挺长时间以前了)的时候,发布Windows10的时候,微软宣布新的浏览器将重新开发,关键是后半句引起了 ...
- Tesseract 3 语言数据的训练方法
OCR,光学字符识别 光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程.OCR技术非常专业 ...
- centos SSH配置详解
基本概念 linux自带的ssh为OpenSSH ssh协议提供两种用户认证方式 1. 基于口令的安全认证:使用用户名.密码的方式对登录用户进行认证 2. 基于密钥的安全认证:使用公钥和私钥对的方 ...
- Android编程中常用的PopupWindow和Dialog对话框
注意:PopupWindow组件的使用问题,PopupWindow是一个阻塞对话框,如果你直接在Activity创建的方法中显示它,则会报错:android.view.WindowManager$Ba ...
- 安装Ubuntu 14.04后要做的5件事情
转自安装Ubuntu 14.04后要做的5件事情 Ubuntu目前是世界上最流行的Linux操作系统,它提供了桌面版本和服务器版本,其他流行的Linux发行版本如Linux Mint也是基于Ubunt ...
- Mysql Not in有null值查询的问题
今天发现Mysql的not in使用的一个问题,大致是: select * from A where id not in (select fid from B). 发现查询结果无论如何都是0条记录.后 ...
- Motion on Ubuntu
Motion is a program that monitors the video signal from one or more cameras and is able to detect if ...
- Fast UI Draw (Intel出品)
Fast UI Draw in a library that provides a higher performance Canvas interface. It is designed so tha ...