﻿# ASP.NET MVC 開發心得分享 (8)：Routing 設定注意事項

如果剛開始寫 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#)](http://www.asp.net/learn/mvc/view.aspx?__id=08&__language=cs) 文章所介紹的方式，你可能會直接在 RegisterRoutes 加上以下程式碼：

```
routes.MapRoute(
  "Root",
  "",
  new { controller = "Home", action = "Index", id = "" }
);
```

然後把原本那個 routes.MapRoute 方法中的 {controller} 加上 .aspx (如下圖示)，但這會掉入一個很容易犯錯的地方：**忘記將原本的 Default Route 中的 controller = "Home", 移除**！

 ![Global.asax.cs RegisterRoute method](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/f1ca662df86fd9ad4f07-image_6.png "Global.asax.cs RegisterRoute method")

如果你**沒有移除**這段程式，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：

```csharp
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 修改成如下：

```csharp
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 的名稱，產生的網址就會是根目錄( / )。

所以使用者點擊首頁時就會變成這樣：

1.  瀏覽器連結到 http://mysite/ ，並觸發 BrowserCheck() Action
2.  BrowserCheck() Action 轉址到 Url.Action("Index", "Home") 也就是網站根目錄( / )
3.  然後又回到步驟 1，正式開始無窮回圈！

學習 ASP.NET MVC 一定要搞懂 Routing，雖然是簡單的東西，但對於第一次接觸 ASP.NET MVC 的人可能還不太容易理解整個來龍去脈，多寫 Code 遇到一些問題後觀念就會越來越清晰了。

**相關連結**

-   [Using ASP.NET MVC with Different Versions of IIS (C#)](http://www.asp.net/learn/mvc/view.aspx?__id=08&__language=cs)
-   [Providing Website Navigation with SiteMaps (C#)](http://www.asp.net/learn/mvc/tutorial-20-cs.aspx)
