如果剛開始寫 ASP.NET MVC 的人,可能都會很自然的參考預設 ASP.NET MVC Web Application 的範本設定,尤其是在 Global.asax.cs 中的 RegisterRoutes 方法,但如果 ASP.NET MVC 越寫越多之後,可能就會開始想要做點變化了,今天我就來分享幾個應注意的事。
1. 讓 IIS6 安裝設定 ASP.NET MVC 時不用修改 萬用字元應用程式對應 (Wildcard Script Map)
預設 ASP.NET MVC 專案新增完後,在 Global.asax.cs 中有個 RegisterRoutes 方法:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
如果你直接參考 Using ASP.NET MVC with Different Versions of IIS (C#) 文章所介紹的方式,你可能會直接在 RegisterRoutes 加上以下程式碼:
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
然後把原本那個 routes.MapRoute 方法中的 {controller} 加上 .aspx (如下圖示),但這會掉入一個很容易犯錯的地方:忘記將原本的 Default Route 中的 controller = "Home", 移除!
如果你沒有移除這段程式,Root 這個 Routing 規則等於是完全沒用的,永遠不會執行到!
在簡單的 Routing 下雖不會導致任何問題,但若需要用到此文章第三個開發技巧時,就有很大的關係了。
2. 首頁的 Routing 網址跟 Global.asax.cs 中的 Routing 設定有很大的關係
如上圖所示,Default 與 Root 這兩個 Routing 的撰寫順序是有差別的,當你利用 HtmlHelper 或 UrlHelper 產生連結時,差別就在於顯示連結不一樣:
<%= Html.ActionLink("Home", "Index", "Home")%>
Url.Action("Index", "Home");
第一種:Default 在前、Root 在後
routes.MapRoute(
"Default", // Route name
"{controller}.aspx/{action}/{id}", // URL with parameters
new { action = "Index", id = "" } // Parameter defaults
);
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
所得到的連結將會是 /Home.aspx(首頁網址比較醜)
第二種:Root 在前、Default 在後
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
routes.MapRoute(
"Default", // Route name
"{controller}.aspx/{action}/{id}", // URL with parameters
new { action = "Index", id = "" } // Parameter defaults
);
所得到的連結將會是 / (首頁網址比較漂亮)
3. 設定「網站首頁」依據不同瀏覽器自動轉址到不同首頁
當你的網站同時提供多種平台的網頁(例如:桌上、PDA、WAP、…),你可能會想在首頁 ( / ) 加上自動瀏覽器型別的判斷,用以轉向到不同的網站首頁。這個技巧就跟上述第一個注意事項所示的錯誤有很大的關係,寫不好就會導致網頁轉向的無窮迴圈。
程式範例如下,在 HomeController 下新增一個 BrowserCheck() Action:
public ActionResult BrowserCheck()
{
// Windows CE (Pocket PC)
if (!String.IsNullOrEmpty(Request.Headers["UA-OS"])
&& Request.Headers["UA-OS"].Contains("Pocket PC"))
{
return Redirect("/PocketPC");
}
// SymbianOS
else if (!String.IsNullOrEmpty(Request.Headers["User-Agent"])
&& Request.Headers["User-Agent"].Contains("SymbianOS"))
{
return Redirect("/SymianOS");
}
else
{
return Redirect(Url.Action("Index"));
}
}
接著在 Global.asax.cs 中的 RegisterRoute 修改成如下:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { action = "Index", id = "" });
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "BrowserCheck", id = "" });
}
由於我們在 BrowserCheck() Action 中的預設的轉址(Redirect)路徑為 Url.Action("Index"),所產生的連結是依據 Global.asax.cs -> RegisterRoute 方法中的規則所決定的,如果 Routing 寫錯就會導致每次都會再連到首頁 ( / ) 導致無窮迴圈, 以下是發生無窮迴圈的錯誤範例:
首先,錯誤的 Routing 定義如下:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Home",
"",
new { controller = "Home", action = "BrowserCheck", id = "" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" });
}
如果你用瀏覽器直接打 http://mysite/ 所執行的永遠是 "Home" Routing,不可能跑到 "Default" Routing
如果你利用 HtmlHelper 或 UrlHelper 產生首頁連結時,如下範例:
Url.Action("Index", "Home");
這時會選用 “Default”Routing 的 Rule,因為只有這個 Rule 最符合,因為你放了 controller 參數的預設值,所以網址列並不會出現 Controller 的名稱,產生的網址就會是根目錄( / )。
所以使用者點擊首頁時就會變成這樣:
- 瀏覽器連結到 http://mysite/ ,並觸發 BrowserCheck() Action
- BrowserCheck() Action 轉址到 Url.Action("Index", "Home") 也就是網站根目錄( / )
- 然後又回到步驟 1,正式開始無窮回圈!
學習 ASP.NET MVC 一定要搞懂 Routing,雖然是簡單的東西,但對於第一次接觸 ASP.NET MVC 的人可能還不太容易理解整個來龍去脈,多寫 Code 遇到一些問題後觀念就會越來越清晰了。
相關連結