2012年10月4日 星期四

ASP.NET MVC 資料分頁與 Route - Part.1


用 ASP.NET MVC 所開發的網站與 ASP.NET Web Forms 網站有一個比較名顯的不同的就是「網址」,ASP.NET MVC 不像 Web Forms 網站專案,是由一個一個的 ASPX 檔案所構成的,任何的 Request 都是需要透過 Route,然後再到 Controller 的 Action 進行處理,所以 ASP.NET MVC 的網站不像 ASP.NET Web Forms 網站的網址那樣會需要有個「aspx」的檔案結尾,Web Forms 可以透過例如 Url Rewrite 或是使用 URL Routing ( .NET 4.0 ) 來達到與 ASP.NET MVC 一樣的網址格式,

例如:Easy URL routing in ASP.NET 4.0 web forms

ASP.NET MVC 預設的 Route 設定就已經可以應付絕大部分的狀況,但有時候難免會想要讓 URL 看起來更漂亮一些,或是說讓網站因為 URL 的關係而有比較好的 SEO,總之就是讓 URL 可以更為直覺與方便輸入,接下來簡單敘述 ASP.NET MVC 在分頁功能下的 Route 設定。

 


操作示範使用 ASP.NET MVC 4.0 開發,範例資料庫使用「Northwind」,分頁功能使用「MvcPaging 2.0」

初學習 ASP.NET MVC 的 Route (路由)設定,建議先詳讀 MSDN 的「ASP.NET 路由」:

http://msdn.microsoft.com/zh-tw/library/cc668201(v=vs.100).aspx

MvcPaging 2.0

http://blogs.taiga.nl/martijn/2012/04/23/mvcpaging-2-0/

 

我這邊已經預先做好一個基本的產品資料列表的網頁,然後也使用了「MvcPaging 2.0」來完成分頁的功能需求,

如圖:

image

 

因為是使用 ASP.NET MVC 預設的 Route 設定,所以每個分頁的網址都是這個樣子:

「http://localhost:5511/Product?page=2」

「http://localhost:5511/Product?page=3」

「http://localhost:5511/Product?page=8」

 

預設的 Route 設定如下:

routes.MapRoute(
    "Default", // 路由名稱
    "{controller}/{action}/{id}", // URL 及參數
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數預設值
);

 

PS.
ASP.NET MVC 4 已經沒有在 Global.asax 裡面放置上面的預設 Route 設定,因為已經預設在底層了,所以不要看 Global.asax 中沒有預設的 Route 設定就把上面的程式給加進去,這樣一來是會出現錯誤的!

image

 

ProductController 的 Index action方法如下:

public ActionResult Index(int page = 1)
{
    int currentPageIndex = page < 0 ? 0 : page - 1;
 
    var query = productService.GetAll()
        .OrderBy(x => x.CategoryID)
        .ThenBy(x => x.ProductID);
 
    ViewData.Model = query.ToPagedList(currentPageIndex, DefaultPageSize);
    ViewBag.CurrentPage = page;
    return View();
}

 

因為 Index() 所輸入的參數並無預設 Route 的 page 參數,所以 page 參數名稱與值就會用「? 」接在 URL 的後面,

「http://localhost:5511/Product?page=2」

上面這樣的網址並沒有什麼太大的問題,但就是不太直覺,其實我們可以改個方式,例如:

「http://localhost:5511/Product/Page/2」

「http://localhost:5511/Product/2」

修改過後的網址是不是看起來就比較直覺一些呢?

 

我們先來修改 Route 設定,讓分頁 URL 使用http://localhost:5511/Product/2這樣的形式,其實這樣的 URL 形式設定是最為簡單的,如下:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
 
        RegisterRoutes(RouteTable.Routes);
 
        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
 
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        routes.MapRoute(
            "Product_Default", // 路由名稱
            "Product/{page}", // URL 及參數
            new { controller = "Product", action = "Index", page = UrlParameter.Optional } // 參數預設值
        );
    }
 
}

再來看一次 Product_Default 所對應使用的 Index Action 方法,Product_Default 設定的「URL 及參數」及「參數預設值」對應到你所指定的 Action 方法的名稱與輸入參數名稱,

public ActionResult Index(int page = 1)
{
    int currentPageIndex = page < 0 ? 0 : page - 1;
 
    var query = productService.GetAll()
        .OrderBy(x => x.CategoryID)
        .ThenBy(x => x.ProductID);
 
    ViewData.Model = query.ToPagedList(currentPageIndex, DefaultPageSize);
    ViewBag.CurrentPage = page;
    return View();
}

最後來觀察程式執行後的結果:

一開始我們輸入「http://localhost:5511/Product」這樣的 URL,這樣的 URL 結構正好匹配到我們所設定的 Route 設定「Product_Default」,這個 Route 設定對於 page 參數是有給予預設值,所以輸入的 URL 如果沒有 page 參數,那麼 page 就會以預設值「1」傳給 Index(),

image

接著直接輸入「http://localhost:5511/Product/6」這樣的 URL,就可以顯示第六頁的產品資料,

image

MvcPaging 分頁列上的頁碼連結會依據目前 URL 的結構所匹配 Route 設定而產生相同 Route 設定格式的 URL,

image

 

接下來我們依據上面的 Route 設定方式,這次將 URL 設定改為「http://localhost:5511/Product/Page/2」的格式,

增加 Route 設定:

新增加的 Route 設定添加在上一個範例的 Route 設定上面,

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
    routes.MapRoute(
       "Product_Page", // 路由名稱
        "Product/Page/{page}", // URL 及參數
        new { controller = "Product", action = "Index", page = UrlParameter.Optional } // 參數預設值
    );
 
    routes.MapRoute(
       "Product_Default", // 路由名稱
        "Product/{page}", // URL 及參數
        new { controller = "Product", action = "Index", page = UrlParameter.Optional } // 參數預設值
    );
 
}

 

其他的程式都不必做任何變動,接著觀察執行的結果,輸入「http://localhost:5511/Product/Page/1」後,所顯示的就是第一頁的資料,而如果只輸入「http://localhost:5511/Product/Page」也會顯示第一頁的資料,雖然沒有給 page 的參數值,但是在 Index() 方法中是有給予 page 的預設參數值「1」,所以沒有給 page 參數值時就會自動帶入「1」顯示第一頁的資料

image

MvcPaging 分頁列的各頁碼連結的 URL 也依據新的 Route 設定值來產生匹配的 URL 格式,

image

 

Route 設定值的匹配是會依照在 Global.asax 的設定順序由上而下的去做匹配的動作,假如 URL 未能匹配第一個 Route 設定值,那麼就會往下找第二個,再找不到的話就繼續往下尋找,如果某個 Route 設定值匹配成功後就不會往下找,所以 Route 設定值的順序是要由大而小的排放下去。

怎麼去看 Route 設定值的匹配或是除錯呢?可以參考 demo 的一篇文章「ASP.NET MVC 如何簡單測試 Routes」,這篇文章當中有介紹到一個工具「Route Debugger」,可以藉由這個工具來觀察 Route,現在我們可以使用 NuGet 來安裝這個套件,

image

安裝完成後,在 Web.Config 的 appSettings 會增加一個設定值「RouteDebugger:Enabled」,預設是 true,ASP.NET MVC 4.0 於安裝 RouteDebugger 後是不需要增加程式碼,而之前的 ASP.NET MVC 版本就必須要增加程式碼,demo 的文章中有告訴我們應該增加什麼內容。

image

重新執行網頁,可以看到原本的網頁下方多增加了 Route Debugger 的區塊,這個區塊中就可以觀察到 Route Debugger 的匹配狀況,

image

如果不希望顯示 Route Debugger 的內容時,就去修改 Web.Config 的「RouteDebugger:Enabled」為 false 就可以。

以上是簡單且基本的 Route 設定修改,

 

備註:其實另一個也可以用來觀察 Route 的工具是「glimpse」,kevin 之前也曾經寫了幾篇文章的介紹。


系列文章,下一篇:

ASP.NET MVC 資料分頁與 Route - Part.2

 

以上

5 則留言:

  1. 想請問您是如何把asp.net 和 C#的 CODE貼在BLOGSPOT上?

    回覆刪除
    回覆
    1. 我編寫 Blog 文章是使用 Windows Live Writer,只要有裝 Windows Live(MSN)就應該會有,
      或是以下的連結下載程式:
      http://www.microsoft.com/zh-tw/download/details.aspx?id=8621

      然後 WLW 有很多的 Plugin 程式可以使用,貼程式的 Plugin 我有使用兩種,分別是:
      Code Snippet 以及 Source Code

      你可以到以下的網頁中找尋適合的外掛程式來使用,
      http://plugins.live.com/writer/browse?orderby=featured&page=1

      相關 WLW 外掛程式的安裝與使用,請 Google 相關文章與資源,這邊不再詳述。

      刪除
  2. COOL!
    那我會去找看看
    謝謝你哦^^

    回覆刪除
  3. 可惜這個套件似乎沒有特定URL供檢視?
    所以公開發布的版本需要改成false
    開發階段要再改成Enabled
    在git操作上也比較麻煩一點

    回覆刪除
    回覆
    1. 透過 CI/CD 的過程去修改 Web.config 的設定內容就可以了

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。