標籤

2011年11月8日 星期二

MVC Control 路由與 URL Routing 設定注意事項


Routing 設定注意事項

參考The will will Web

在 Global.asax.cs 中的 RegisterRoutes 方法,但如果 ASP.NET MVC 越寫越多之後,可能就會開始想要做點變化了
1. 讓 IIS6 安裝設定 ASP.NET MVC 時不用修改 萬用字元應用程式對應 (Wildcard Script Map)
預設 ASP.NET MVC 專案新增完後,在 Global.asax.cs 中有個 RegisterRoutes 方法:


        routes.MapRoute( _
                "Default", _
                "{controller}/{action}/{id}", _
                New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional} _
            )


可能會直接在 RegisterRoutes 加上以下程式碼:
        routes.MapRoute( _
        "EQuery", _
        "{EQuery}/{name}", _
        New With {.controller = "EQuery", .action = "Search", .id = UrlParameter.Optional} _
        )

然後把原本那個 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", _
                "{controller}/{action}/{id}", _
                New With {.action = "Index", .id = UrlParameter.Optional} _
            )

        routes.MapRoute( _
        "EQuery", _
        "{EQuery}/{name}", _
        New With {.controller = "EQuery", .action = "Search", .id = UrlParameter.Optional} _
            )
所得到的連結將會是 /Home.aspx(首頁網址比較醜)
第二種:Root 在前、Default 在後
        routes.MapRoute( _
        "EQuery", _
        "{EQuery}/{name}", _
        New With {.controller = "EQuery", .action = "Search", .id = UrlParameter.Optional} _
        )

        routes.MapRoute( _
                "Default", _
                "{controller}/{action}/{id}", _
                New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional} _
            )
所得到的連結將會是 / (首頁網址比較漂亮)
3. 設定「網站首頁」依據不同瀏覽器自動轉址到不同首頁
當你的網站同時提供多種平台的網頁(例如:桌上、PDA、WAP、…),你可能會想在首頁 ( ) 加上自動瀏覽器型別的判斷,用以轉向到不同的網站首頁。這個技巧就跟上述第一個注意事項所示的錯誤有很大的關係,寫不好就會導致網頁轉向的無窮迴圈。
程式範例如下,在 HomeController 下新增一個 BrowserCheck() Action:
  1. public ActionResult BrowserCheck()  
  2. {  
  3.     // Windows CE (Pocket PC)  
  4.     if (!String.IsNullOrEmpty(Request.Headers["UA-OS"])   
  5.         && Request.Headers["UA-OS"].Contains("Pocket PC"))  
  6.     {  
  7.         return Redirect("/PocketPC");  
  8.     }  
  9.     // SymbianOS  
  10.     else if (!String.IsNullOrEmpty(Request.Headers["User-Agent"])   
  11.              && Request.Headers["User-Agent"].Contains("SymbianOS"))  
  12.     {  
  13.         return Redirect("/SymianOS");  
  14.     }  
  15.     else  
  16.     {  
  17.         return Redirect(Url.Action("Index"));  
  18.     }  










接著在 Global.asax.cs 中的 RegisterRoute 修改成如下:

  1. public static void RegisterRoutes(RouteCollection routes)  
  2. {  
  3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
  4.   
  5.     routes.MapRoute(  
  6.         "Default",  
  7.         "{controller}/{action}/{id}",  
  8.         new { action = "Index", id = "" });  
  9.   
  10.     routes.MapRoute(  
  11.       "Root",  
  12.       "",  
  13.       new { controller = "Home", action = "BrowserCheck", id = "" });  
  14. }  

由於我們在 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 的名稱,產生的網址就會是根目錄( )。
所以使用者點擊首頁時就會變成這樣:
  1. 瀏覽器連結到 http://mysite/ ,並觸發 BrowserCheck() Action
  2. BrowserCheck() Action 轉址到 Url.Action("Index", "Home") 也就是網站根目錄( )
  3. 然後又回到步驟 1,正式開始無窮回圈!
學習 ASP.NET MVC 一定要搞懂 Routing,雖然是簡單的東西,但對於第一次接觸 ASP.NET MVC 的人可能還不太容易理解整個來龍去脈,多寫 Code 遇到一些問題後觀念就會越來越清晰了。










英文說明
http://www.pluralsight-training.net/microsoft/players/PSODPlayer?author=scott-allen&name=mvc3-building-controllers&mode=live&clip=0&course=aspdotnet-mvc3-intro

MSDN說明
http://msdn.microsoft.com/zh-tw/library/cc668201(VS.90).aspx
http://msdn.microsoft.com/zh-tw/magazine/dd695917.aspx

ASP.NET 路由與 URL 重寫的比較


路由定義 比對 URL 的範例
{controller}/{action}/{id}
/Products/show/beverages
{table}/Details.aspx
/Products/Details.aspx
blog/{action}/{entry}
/blog/show/123
{reporttype}/{year}/{month}/{day}
/sales/2008/1/5
{locale}/{action}
/en-US/show
{language}-{country}/{action}
/en-US/show
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
    RegisterRoutes(RouteTable.Routes)
End Sub

Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    Dim urlPattern As String
    Dim categoryRoute As Route

    urlPattern = "Category/{action}/{categoryName}"
    categoryRoute = New Route(urlPattern, New CategoryRouteHandler)
    categoryRoute.Defaults = New RouteValueDictionary(New With _
        {.categoryName = "food", _
         .action = "show"} )

    routes.Add(categoryRoute)
End Sub

ASP.NET 路由處理 URL 要求時,範例中顯示的路由定義 (categoryName  food 以及 action  show 的預設值) 
會產生如下表列出的結果:
URL 參數值
/Category
action = "show" (預設值)
categoryName = "food" (預設值)
/Category/add
action = "add"
categoryName = "food" (預設值)
/Category/add/beverages
action = "add"
categoryName= "beverages"
從路由建立 URL




Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    routes.Add(New Route( _
      "Category/{action}/{categoryName}", _
      New RouteValueDictionary(New With _
          {.categoryName = "food", _
           .action = "show"}), _
           New CategoryRouteHandler()) )
End Sub
Dim urlParameters As RouteValueDictionary
urlParameters = New RouteValueDictionary(New With {.categoryName = "beverages", _
        .action = "summarize"})
HyperLink1.NavigateUrl = RouteTable.Routes.GetVirtualPath _
    (context, urlParameters).VirtualPath
這段程式碼執行時,HyperLink1 控制項會在 NavigateUrl 屬性中加入 "Category/summarize/beverages" 這個值。
當您要從路由建立 URL 時,可以加入路由的名稱,從而指定要使用哪一個路由
名稱Framework 行為產生方法
ContentResult您可以將字串值直接將 HTTP 回應。內容
EmptyResult不會寫入 HTTP 回應。
FileContentResult會在檔案 (表示為位元組陣列) 的內容,並將內容寫入為 HTTP 回應。檔案
FilePathResult在指定的位置會在檔案的內容,並寫入 HTTP 回應的內容]。檔案
FileStreamResult接受控制器所產生檔案資料流,並寫入 HTTP 回應的資料流中。檔案
HttpUnauthorizedResult授權檢查失敗時,授權篩選器會使用一個特殊的結果。
JavaScriptResult回應用戶端使用用戶端執行指令碼。JavaScript
JsonResult回應用戶端 JavaScript Object Notation (JSON) 資料。json
RedirectResult重新導向至新的 URL 的用戶端。重新導向
RedirectToRouteResult呈現指定的檢視 (通常是在 AJAX 的案例中使用) 的 HTML 片段的回應。RedirectToRoute / RedirectToAction
PartialViewResult呈現指定的檢視 (通常是在 AJAX 的案例中使用) 的 HTML 片段的回應。PartialView
ViewResult呈現指定的檢視,並以 HTML 用戶端回應。檢視














沒有留言:

使用 DiskSpd 測試磁碟效能

  DiskSpd 是微軟創建的命令行磁碟測試工具。它結合了強大的IO工作負載定義來測量磁碟效能。由於它支援自由配置和調整參數,使其成為存儲效能測試、驗證和基準測試的理想工具。 步驟 1. 從 GitHub (說明) https://github.com/Microsoft/di...