ASP.NET Web API 心得筆記 (4) Web API Routing

如果你已經熟悉 ASP.NET MVC,你會發現 Web API Routing(路由)與 MVC 非常類似。主要差異在 Web API 使用 HTTP Method ( GET, POST, PUT, DELETE ...) 而不是使用 URI 路徑來選擇 Action。你也可以在 Web API 裡使用 MVC 樣式的路由。以下討論專注在 Web API 且可以沒有 ASP.MVC 基礎。

Routing Tables, 路由表

在 ASP.NET Web API,一個 controller 是一個 class(類別) 以處理 HTTP 請求(requests)。在 controller 裡所有的公開方法(public  methods)都稱為 Action方法 或簡稱 Action。當 Web API Framework 接收到一個請求,它路由請求到一個 Action。

Framework 會使用路由表(Routing Table),決定那一個 Action 會被呼叫。如果你在 ASP.NET 裡使用 Web API,路由表會定義在 Global.asax 檔案中。預設使用 Visual Studio 去新增一個 Web API 專案,專案樣版會建立預設路由給你:

routes.MapHttpRoute( _
    name:="DefaultApi", _
    routeTemplate:="api/{controller}/{id}", _
    defaults:=New With {.id = RouteParameter.Optional} _
)

注意,如果你使用 self-host Web API,你必須在 HttpSelfHostConfiguration物件 上直接設定路由表(這未來我們會討論)。
每個實體(entry)在路由表裡都包含一個路由樣板(route template)。Web API 的路由樣板預設是 "api/{controller}/{id}",此樣板裡,"api" 是文字路徑片段,{controller} 和 {id} 是定位變數

當 Web API Framework 接收到一個 HTTP 請求,它會去嘗試比對 URI 對路由表的路由樣板之一, 如果沒有符合的路由,Client 會收到一個 404 錯誤。例如,以下 URI 會符合預設路由:

  • /api/contacts
  • /api/contacts/1
  • /api/products/ApplePie



不管如何,下面的 URI 不會符合,因為它遺失 "api" 片段:

  • /contacts/1

注意,使用 "api" 在路由裡避免與 ASP.NET MVC 路由衝突。這樣,你能使用 "/contacts" 在 MVC controller,使用 "/api/contacts" 在 Web API controller。當然,如果你不喜歡這種慣例,你可以自行修改預設路由表。
當一個符合的路由發現,Web API 會選擇 controller 與 action:

  • 搜尋 controller,Web API 新增 "Controller" 到 {controller} 變數的值。
  • 搜尋 action,Web API 查看 HTTP 方法,然後查看 action,哪一個名稱的開始與是 HTTP 方法名稱。例如,一個 GET 請求,Web API 會查看那一個 action 是以 "Get..."  開頭,像是 "GetContact" 或 "GetAllContacts"。此慣例使用在 GET, POST, PUT, DELETE 方法。你也能在 controller 裡使用屬性(attributes)去啟用其他 HTTP 方法。
  • 在路由樣板裡其他定位變數,像是 {id},會對應至 action 的參數。

讓我們看個例子,假如你定義以下 controller:

Imports System.Web.Http
Imports System.Net.Http

Public Class ProductsController
    Inherits ApiController

    Sub GetAllProducts()
    End Sub

    Function GetProductById(id As Integer) As IEnumerable(Of Products)
    End Function

    Function DeleteProduct(id As Integer) As HttpResponseMessage
    End Function
End Class

以下有一些可能 HTTP 請求:

Web API Routing and HTTP Method
HTTP MethodURI路徑Action參數
GET/api/productsGetAllProducts(無)
GET/api/products/5GetProductById5
DELETE/api/products/5DeleteProduct5
POST/api/products(無符合)

留意 URI 的 {id} 段落,如果存在,會對應到 action 裡的 id 參數。上述範例, controller 定義了兩個 GET 方法,一個 id 參數一個 id 參數。另外,POST 請求會失敗,因為在 controller 裡沒有定義 "Post..." 方法。

路由參數, Routing Variations

接下來我們討論路由參數。

HTTP 方法, HTTP Methods

Web API 使用HTTP 方法的名稱慣例(naming convention)來替代。你也能明確在 action 方法上指定使用 HttpGet, HttpPost, HttpPut, HttpDelete 屬性

例如,以下的 FindProduct 方法會對應至 GET 請求:

<HttpGet>
Function FindProduct(id As Integer) As Products
End Function

允許多個 HTTP 方法在一個 action,或允許 HTTP 方法(GET, POST, PUT, DELETE)以外使用 AcceptVerbs 屬性,取得採用的 HTTP 方法清單。

<AcceptVerbs("GET", "HEAD")>
Function FindProduct(id As Integer) As Products
End Function

' WebDAV 方法
<AcceptVerbs("MKCOL")>
Sub MakeCollection()
End Sub

Action 名稱的路由

在預設路由樣板,Web API 使用 HTTP 方法來選擇 action。不管如何,你也能建立一個 URI 含有 action 名稱的路由。

routes.MapHttpRoute(
    name:="ActionApi",
    routeTemplate:="api/{controller}/{action}/{id}",
    defaults:=New With {.id = RouteParameter.Optional}
)

此路由樣板,在 controller 裡的 action 方法會與 {action} 參數對應。使用此種路由樣式,你必須明確指定允許屬性在 HTTP 方法。例如,在 controller 裡有一個 Details 方法:

<HttpGet>
Function Details(id As Integer) As String
End Function

一個 "/api/products/details/1" 的 GET 請求 將會對應至 Details 方法。這種路由樣式非常類似 ASP.NET MVC,或是接近一個 RPC-style API。在一個 RESTful API,你應該避免在 URI 使用動詞(verbs),因為 URI 應該是定義資源而不是action。

非 Action

如果要預防一個 action 被呼叫,可以使用 NonAction 屬性。這是一個信號跟 Framework 說此方法不是一個 action 方法。

' 不是 action 方法
<NonAction>
Function GetPrivateData() As String
End Function

參考資料

9 則留言:

  1. 網誌管理員已經移除這則留言。

    回覆刪除
  2. 版主您好, 我今天有依照您的文章實作一下WebAPI,但是我沒有完全的使用MVC環境,反而是將一部份的程式碼稍微改一下(變動幅度極小),並且放到現在正常運行的Web Form環境。大至上如這篇文章所示:http://goo.gl/C4WUQ,並且在本機的VS環境中,可以順利的運行起來,並利用GET看到相關的XML回傳。

    我現在很大的困擾是,我正式Server之前是.NET4.0,因為要測試WebAPI所以安裝了4.5,可是當我把Model跟Controller這些.CS手動複製上去網站,完全一樣的程式碼卻連compile都過不了。

    他顯示這樣的錯誤:

    編譯器錯誤訊息: CS0234: 命名空間 'System.Web' 中沒有型別或命名空間名稱 'Http' (您是否遺漏了組件參考?)

    而我的controller的Code是:
    行 5: public class MemberAuthController : System.Web.Http.ApiController
    行 6: {

    就算我使用 using System.Web.Http,compiler 一樣傳回相同的錯誤訊息。看起來是.NET 4.5的安裝註冊有問題,版主是否有遇過,或者有怎樣的建議解法嗎?

    回覆刪除
    回覆
    1. 這篇"http://goo.gl/C4WUQ"文章是ASP.NET Web API Preview版本所寫,Preview版本和RTM版有許多小多差異。

      如果沒發生意外的話,下個月我有寫一本ASP.NET MVC 4的書應該會出版,裡面會有非常大量且完整ASP.NET Web API的介紹,大概你會碰的地雷,我都碰到了。全部寫在書裡面。

      另,不是不在這裡回答你,而是一個問題,我在書裡都要花幾頁來交代了,實在無法用三言兩語在此交代。如果不是要立即上線的專案,請再等等,謝謝。

      刪除
  3. 嗯,我了解,謝謝您的回覆。其實重點就在於裝了.NETFramework4.5後,並不代表就可以直接sourceCode跑MVC或WebAPI,應該還要再跑一些獨立安裝檔,來部署透過NuGet取得的DLL,當這些DLL被滿足時,compiler就可以找到了。
    環境感覺要到.NET5才成熟吧,跟當初的AJAX剛出現一樣。另,請問版主的書名是?出版時我想要去買一本。

    回覆刪除
    回覆
    1. 碁峰出版社的那一本就是了!^_^
      多留意我的Blog,或是G+專頁,等出版了我當然會寫篇文好好介紹一下。

      刪除
  4. 版主,想要再請教您一個問題。
    在您之前的文章中,model都是屬於比較簡單的設計,只有一個階層,但如果要做到兩個階層的設計,應該要怎麼樣寫會比較好?例如我回傳的xml(或json)裡面,想要表示這些資料,那麼model要怎麼寫才可以完成這樣的概念:

    <result>
      <name>john</name>
      <data>
        <item type="A">Things1</item>
        <item type="B">Things2</item>
      </data>
    </result>

    回覆刪除
  5. 瞭解一下JSON:「http://blog.kkbruce.net/2011/01/json.html」。
    都已經用到Web API了,除非是提供給只能解析XML的Client端,不然未來的主流應該都是以JSON為主。(雖然xml也是web api內建的輸出方式之一)

    關於Model怎麼設計,基本上,就是資料庫的正規化設計,當取得"1對多"的資料時,Web API會幫你轉成JSON進行輸出。

    回覆刪除
    回覆
    1. 您好,我知道JSON,在設計時期的資料輸出我也是採用JSON,我在問題中使用XML來表示是因為這樣比較容易閱讀看的懂。

      因為我常時間都是在WebForm的環境下撰寫,WebAPI都是在網路翻一翻文章試一下,所以對於Model的觀念沒有那麼的強烈,就WebAPI來說,他會自動把我們設計好的類別物件,自動轉換成JSON或XML打出去,可是網路上大部份都是停留在非常簡單的類別寫法,這也就是為什麼我想要向您請教一下,以我上面打的那個期望輸出的範例,可否給個較複雜類別的範例寫法?

      不然像這種簡單的類別寫法,與controller的輸出,無法達到真實世界的運用啊!
      public class Member
      {
      public int id { get; set; }
      public string name { get; set; }
      }

      public Member getMember() {
      Member oMember = new Member {id: "A0001", name: "john"};
      return oMember;
      }

      刪除
    2. 1. VS擴充:http://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Sample-Browser-Visual-Studio-Extension?mc_id=opengraph

      2. 桌面版:http://1code.codeplex.com/

      範例的話,用一下這兩套,它們都是微軟官方的套件,集合了所有超過3500套程式碼範例,找一下關鍵字"web api"就有算"堆"的範例。

      與寫文章不同,裡面的範例都是完整的範例,寫文章通常只是一個點的說明,請見諒。

      刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。