2013年12月16日 星期一

ASP.NET MVC - 使用 Attribute Routing

Attribute Routing 在原作者 Tim McCall 捐獻給 .NET Framework 後,在 ASP.NET MVC 5 與 ASP.NET Web API 2 的專案裡就可以使用,如果是使用 ASP.NET MVC 5 專案的話,可以在 SystemWeb.Mvc 命名空間裡看到,

image

這一篇將會對於 Attribute Routing 的使用做個簡單的說明。

 


AttributeRouting

http://attributerouting.net/

https://github.com/mccalltd/AttributeRouting

https://github.com/mccalltd/AttributeRouting/wiki

image

如果是其他版本的 ASP.NET MVC 專案,例如 4.0 , 3.0 的版本也是可以使用,但是要另外從 NuGet 裡將 Attribute Routing 給加入到專案,

image

 

事前準備

Attribute Routing 的設定方式並不是很複雜,請先將 AttributeRouting 官網的說明以及 AttributeRouting 在 GitHub 上的 Wiki 先看過一遍,就可以知道基本的使用方法,只需要在 Controller 或是 Action 方法上標注 Route 的 Attribute 然後加入 Route 路徑所使用的名稱就可以了,但是有一個動作記得要先做,就是在 ~/App_Start/RouteConfig.cs 裡要加入「routes.MapAttributeRoutes()

ASP.NET MVC 5 專案

image

ASP.NET MVC 4 專案

image

 

在已經公開的 ASP.NET MVC 5.1 RC1 裡,從官方所公開的 Sample 專案裡,並沒有在 ~/App_Start/RouteConfig.cs 裡加入「route.MapAttbibuteRoute()」,

image

並不是說不用加入 route.MapAttbibuteRoute() 的使用,而是可以在另外的地方使用不一樣的方式,在 Global.asax 裡要加入 Attribute Routes 的註冊使用,其實作法都是一樣的。

image

 

操作示範

以下的操作示範將會以 ASP.NET MVC 5 所整合的 AttrobuteRouting 為主,使用上會與 Tim McCall 的版本會略有不同,所以要特別注意。

在 Controller 類別上標注 RoutePrefix 然後指定路徑名稱「Home」,就表示進入這個 Controller 要使用「Home」,

image

如果想要改用別的路徑名稱進入 HomeController 的話,可以在 RoutePrefix 裡使用其他的名稱。

image

註:使用整合進 .NET Framework 的 AttributeRouting,Controller 只能使用一個 RoutePrrfix。

 

設定 Controller 預設的 Action

可以在 Controller 上使用 Route attribute,然後指定進入這個 Controller 預設的 Action,

image

 

Action 使用 Route attribute

在 Action 方法上可以標注多個 Route attribute,這邊建議可以在 Route attribute 上面加上各個 Route 設定所預設使用的路徑註釋,這樣會更加清楚各個 Route 設定的對應,

image

image

image

 

Route Constraints

當一個 Action 方法有需要輸入參數的時候,如果想要限定輸入參數的條件時,就可以在 Route attribute 裡加入 Route Constraints 來加以限制,例如我另外建立了一個 ProductController,然後加入一個 ListByCategory 的 Action 方法,方法的參數是要輸入使用 CategoryName 字串,一定要輸入參數值,但是最小長度為 2 最大長度為 15,所以設定的方式如下:

image

有關 Route Constraints 的使用,可以參考 AttributeRouting 的官網或是 Wiki 說明,

image

image

或是也可以參考「Attribute Routing in ASP.NET MVC 5 - .NET Web Development and Tools Blog」的說明,

image

 

使用多個 Route attribute

一個 Action 方法可以使用多個 Route attribute,以下的例子是依據輸入的國家與郵遞區號顯示客戶資料,

image

localhost:15227/Customer/Brazil

image

localhost:15227/Customer/Brazil/05487-020

image

 

日期限制

這邊用一個簡單的例子來做說明,假如我們想要用指定日期來列出訂單資料的話,可以用以下的設定,

image

image

image

但如果我們想要列出某一年份或是某一年某月的訂單資料呢?這邊就不能用上面的設定方式,但是另外建立一個 Action 方法然後再做 Route 設定,如下:

image

我們可以使用 Route Constraints 來設定傳入參數的限制,年月日都必須是數字,年份可以設定最小與最大值,不過我這邊是沒有做設定,月份設定最小為 1 最大為 12,日設定最小為 1 最大為 31。

其實這個 ListByDateRange 方法的功能與剛才的 ListByDate 有所重疊,兩個可以並存,但是輸入完整日期就不會進入 ListByDateRange 方法,因為 ListByDate 的 Route 設定會比 ListByDateRange 更早被 Mapping 到,所以剛才的 ListByDate 方法就可以不用了,查詢指定訂單日期的功能就可以用 ListByDateRange 方法,以下是 ListByDateRange 方法的完整內容:

// Get: /Order/1997
// Get: /Order/1997-7
// Get: /Order/1997/7
// Get: /Order/1999-7-29
// Get: /Order/1999/7/29
[Route("{year:int}")]
[Route("{year:int}-{month:int:min(1):max(12)}")]
[Route("{year:int}/{month:int:min(1):max(12)}")]
[Route("{year:int}-{month:int:min(1):max(12)}-{day:int:min(1):max(31)}")]
[Route("{year:int}/{month:int:min(1):max(12)}/{day:int:min(1):max(31)}")]
public ActionResult ListByDateRange(int year, int? month, int? day)
{
    List<Order> orders = new List<Order>();
 
    var query = db.Orders
                  .Include(o => o.Customer)
                  .Include(o => o.Employee)
                  .Include(o => o.Shipper);
 
 
    if (!month.HasValue && !day.HasValue)
    {
        var startDate = new DateTime(year, 1, 1);
        var endDate = new DateTime(year, 12, 31);
 
        query = query.Where(x => x.OrderDate.HasValue
                                 && x.OrderDate.Value >= startDate
                                 && x.OrderDate.Value <= endDate);
 
        orders = query.ToList();
    }
    else if (!day.HasValue)
    {
        var startDate = new DateTime(year, month.Value, 1);
        var endDate = month.Value.Equals(12)
            ? new DateTime(year + 1, 1, 1).AddDays(-1)
            : new DateTime(year, month.Value + 1, 1).AddDays(-1);
 
        query = query.Where(x => x.OrderDate.HasValue
                                 && x.OrderDate.Value >= startDate
                                 && x.OrderDate.Value <= endDate);
 
        orders = query.ToList();
    }
    else
    {
        string date = string.Format("{0}/{1}/{2}", year, month, day);
        DateTime orderDate;
 
        if (DateTime.TryParse(date, out orderDate))
        {
            query = query.Where(x => x.OrderDate.HasValue
                                     && x.OrderDate.Value == orderDate);
 
            orders = query.ToList();
        }
    }
    return View("List", orders.OrderBy(x => x.OrderDate).ToList());
}

只輸入年份

image

輸入年份與月份

image

輸入指定日期

image

 


這一篇就先講到這裡,其實 Attribute Routing 的設定還有很多種方式,詳細的使用說明還是先查看 Attribute Routing 官網以及在 GitHub 上的 Wiki,然後再多做練習,如此對 Attribute Routing 的使用就可以得心應手。

使用 Attribute Routing 並不是說就可以拋棄原本在 RouteConfig.cs 的 Route 設定,Attribute Routing 是可以讓我們用夠為彈性的方式來設定 Route。

 

參考連結:

http://attributerouting.net/

https://github.com/mccalltd/AttributeRouting

https://github.com/mccalltd/AttributeRouting/wiki

Attribute Routing in ASP.NET MVC 5 - .NET Web Development and Tools Blog

Release Candidates for ASP.NET MVC 5.1, Web API 2.1 and Web Page 3.1. - .NET Web Development and Tools Blog

 

以上

4 則留言:

  1. Kevin 大:
    在文章前段『就是在 ~/App_Start/RouteConfig.cs 裡要加入「routes.MapAttributeRoutes()」』的 routes.MapAttributeRoutes(),是不是 routes.MapMvcAttributeRoutes() ? :)

    回覆刪除
  2. Kevin 大:
    看來我搞錯了 :P

    回覆刪除
    回覆
    1. 應該說.... 我在那邊的說明是會容易讓人誤解.... 簡言之,我寫得不好 Orz

      刪除
  3. 原來有這麼好用的東西~

    回覆刪除

提醒

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