網頁

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. 原來有這麼好用的東西~

    回覆刪除