2010年6月20日 星期日

ASP.NET 4: Routing

雖然已經使用一段時間的 ASP.NET MVC,但畢竟之前使用 ASP.NET WebForm技術寫的程式多到數不清,無法拋棄,但仍然想要使用 MVC 的 Routing 啊。

經由 ASP.NET MVC 的激勵,在 ASP.NET 4.0 WebForm,特地加上了一組新的 Routing 的API,以支援愈來愈多的 SEO 需求。

單一網頁的 Routing

最簡單的Routing,就是簡單地把一個 Url 對應到一個 WebForm 的 aspx。以下就先簡單地建立一個 WebForm Application。

  1. 建立一個 Web Application,並指定名稱寫 TestRoutes
  2. 在 Global.asax.cs 中,修改 Application_Start 如下
void Application_Start(object sender, EventArgs e)
    {
      System.Web.Routing.RouteTable.Routes.MapPageRoute("about", "About", "~/About.aspx");
    }

測試一下網頁,http://localhost:1295/About.aspxhttp://localhost:1295/About 的結果是相同的。

這樣,我們就簡單地將某一 Request 對應到單一的網頁。

單一參數改成 Routing

建立舊有的網頁

我們先新增一個舊 Style 的 WebForm 網頁 Tag.aspx,並指定 Master Page 如下。

image image

網頁的內容如下

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Tag.aspx.cs" Inherits="TestRoutes.Tag" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  指定 Tag 為 
  <asp:Label Text="text" runat="server" ID="_Tag" />
</asp:Content>

而 CodeBehind 程式如下

using System;

namespace TestRoutes
{
  public partial class Tag : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      _Tag.Text = Request["Tag"];
    }
  }
}

測試一下網頁並加上參數 ?Tag=MVC,結果如預期地顯示如下

image

以上是最簡單不過的 WebForm 程式。現在呢,我想要讓 Url 可以讓搜尋引擎更方便地來搜尋(SEO),故想讓 Url 可以可使用 /Tags/MVC 來達到相同的效果。

改成 Routing 型式

第一步,仍然是在 Global.asax.cs 的 Application_Start 上修改 RouteTable,如下

void Application_Start(object sender, EventArgs e)
    {
      System.Web.Routing.RouteTable.Routes.MapPageRoute("about", "About", "~/About.aspx");
      System.Web.Routing.RouteTable.Routes.MapPageRoute("tag", "Tags/{Tag}", "~/Tag.aspx");
    }
接下來,修改 Tag.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
  //_Tag.Text = Request["Tag"];
  string routeValue = (string)Page.RouteData.Values["Tag"];
  _Tag.Text = routeValue;
}

測試一下網頁 http://localhost:1295/Tags/MVC 果然和之前的結果是一樣的。

image

兩者兼顧

回過頭來測試一下,什麼? http://localhost:1295/Tag.aspx?tag=MVC 反而不能 work? 這非常讓客戶不能接受。我們希望即使SEO 化後,原來的 WebForm 存取方式也能正常。故改 code behind 如下。

protected void Page_Load(object sender, EventArgs e)
{
  _Tag.Text = TagValue;
}

private string TagValue
{
  get
  {
    string fromQuery = Request["Tag"];
    if (string.IsNullOrEmpty(fromQuery))
    {
      string routeValue = (string)Page.RouteData.Values["Tag"];
      return routeValue;
    }
    else
      return fromQuery;
  }
}

經過這次修改後,兩者都可以正常運作了。缺點呢?一看就知道,為了取得使用者要求的 Tag,並且能適用兩種Url 存取方式,必須大動土木地修改 Global.asax.cs 與每個網頁,實在很不人道,而且程式變的更難維護了。之後有空再來解決這一個問題。

使用 RouteValue expression builders

如果在每一頁的 aspx都需要在 code behind 上使用 Page.RouteData來讀取 route value,也太浪費時間了。因此 ASP.NET 4 介紹了一個新的 RouteValue expression builders 來顯示。範例如下

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Tag.aspx.cs" Inherits="TestRoutes.Tag" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  指定 Tag 為 
  <asp:Label Text="text" runat="server" ID="_Tag" />
  <br />
  使用 RouteValue expression builders方式,得到指定 Tag 為
  <asp:Label runat="server" Text="<%$ RouteValue:Tag %>" />
</asp:Content>

簡單地使用 <%$ RouteValue:routeKey%> 語法,就可以讀取 RouteData 了。

製作 RESTFul的連結

要寫出 RESTFul 的連結其實很簡單,只是需要遵循以下RouteValue expression的規則

<%$RouteUrl:RouteName=yourRouteName,yourRouteKey=yourRoutKeyValue%>

image

其中yourRoutName 及 yourRouteKey 是在 Global.asax.cs 中註冊的 RouteTable,yourRouteKeyValue 即是要查詢的值。

舉例來說,若要在首頁(default.aspx)增加一個連結,可以使用如下的設定

<asp:HyperLink NavigateUrl="<%$RouteUrl:RouteName=tag,Tag=MVC %>" runat="server" Text="MVC" />

結論

在 WebForm 中使用這些 Routing 雖然不是難事,但與 MVC 相比起來,相對來說還是較難使用。在 ASP.NET MVC 中,使用 Html Helper 的 ActionLink 是非常直覺的事啊!而 WebForm 卻要記這個RouteValue expression。

範例下載

沒有留言:

Share with Facebook