[Web API] 讓 Web API 支援 OData 查詢

OData 介紹,並且說明如何在 Web API 上使用 OData 的做法。

前言


  OData 這詞也算是目前熱門的詞彙之一,而在 ASP.NET Web API 中也支援了 OData 查詢服務,本篇就來看看如何在 Web API 中加入 OData 來進行操作。

 

OData 為何?


  OData 全名 Open Data Protocol (開放數據協議),是由微軟所提出的協議,主要目的在於透過 HTTP 服務提供 CRUD 的存取服務,最早出現於 WCF Data Service 中,當 Web API 推出時也提供支援 OData 協議,OData 協議建構在 RESTful 服務上,透過公開的 URI 位置進行操作,例如以下的一個 URI 位置範例:

http://localhost:49988/api/products?$top=1

 

  上面網址中 $top 就是 OData 協議中的一個指令,可以發現使用 OData 的操作方式就是在原本的 URI 位置後附加相對應要操作的指令,以下列出常用的 OData 指令:

  • $top:同 T-SQL 的 TOP,指定取得資料的前幾筆。
  • $orderby:同 T-SQL 的 ORDER BY,可指定想排序的欄位。
  • $skip:略過的筆數,可用於資料分頁查詢。
  • $filter:過濾條件,額外區分 eg (等於)、ne (不等於) 、lt (小於)、le (小於等於)、gt (大於)、ge (大於等於)。

 

  上方列出的是常用的指令,當然,因為 OData 還在繼續發展中,所以日後可能將提供更多的指令可以使用,在使用 OData 指令時需要注意指令都需要包含「$」符號,且當如果有多個指令需要串接時,可以使用「&」符號進行串接,例如: /api/products?$top=1&$orderby=Id 。

 

  在 Web API 中透過了使用 OData 的幫助,能夠讓開發者在開發時期專心於資料處理與邏輯的撰寫,能先不考慮因使用者的需求而需要進行某些排序、篩選的問題,開發人員也不必因特定需求而要多撰寫對應方法,只需要最後透過 OData 指令就能夠很有彈性的篩選出目標資料。

 

實作 OData


  首先提醒一點,如果要在 .Net Framework 4.0 上使用 OData,需要額外安裝 OData 擴充組件,我們可以透過使用 NuGet 來安裝 OData 組件,如下:

 

  接下來使用前幾篇所建立的範例程式碼,先來看一段程式碼,以下是未使用 OData 的取得產品資料方法:


public IEnumerable<Product> GetAllProducts()
{
    IEnumerable<Product> products = new ProductDao().GetProducts();
    if (products.FirstOrDefault<Product>() != null)
        return products;
    else
        throw new HttpResponseException(HttpStatusCode.NotFound);
}

 

  接著如果我們要讓這個取得產品資料的方法變成能夠支援 OData 時該如何處理呢? 我們只要稍微改變一下它,看到此方法回傳的型別為 IEnumerable<T> 型別,在使用 OData 時需要將 IEnumerable<T> 型別置換成 IQueryable<T> 型別,為何要使用 IQueryable<T> 而不使用 IEnumerable<T> ?

 

  IQueryable 與 IEnumerable 都是在去執行例如 Count() 方法實際產生列取時才會開始產生 SQL 語法撈取資料,但其實兩者執行時是有差異的,IEnumerable 在建立其列舉時其 SQL 語法就已經固定不變了,如後續再針對此 IEnumerable 附加額外的查詢條件時 SQL 語法也不會變更,附加的查詢則是將資料撈取出來後才在記憶體內再做塞選,而 IQueryable 呢? 參考 MSDN 文件中可以發現 IQueryable 多了一個 IQueryProvider 介面,IQueryProvider 能夠保存列舉前額外增加的查詢條件並變動最終執行的 SQL 語法,如對於實際要去資料庫撈取資料時差異就會顯現,如 LINQ to SQL、Entity Framework,詳情可參考黑大的 關於IQueryable<T>特性的小實驗 文章。

 

  修改回傳 IEnumerable<T> 型別改成 IQueryable<T> 型別後還需要記得在 GetProducts() 方法時加入 AsQueryable<Product> 進行轉換,最後在方法加上 [Queryable] 屬性,如下:


[Queryable]
public IQueryable<Product> GetAllProducts()
{
    IQueryable<Product> products = 
        new ProductDao().GetProducts().AsQueryable<Product>();
    if (products.FirstOrDefault<Product>() != null)
        return products;
    else
        throw new HttpResponseException(HttpStatusCode.NotFound);
}

 

  以上修改完成後,我們就能開始測試看看使用 OData 的效果,如下:

 取得第一筆資料

 

 使用 Price 排序

 

 略過第 1 筆並使用 Price 排序

 

 查詢分類為 MVC 且 ID 為 1

 

  如此就完成使用 OData 協議的查詢功能了,另外如果需要針對 JSON 返回的資料把一些欄位隱藏起來的話,可以加入 System.Runtime.Serialization 組件參考,加入後在 Entity Class 的公開屬性上加入 [IgnoreDataMember] 屬性,如下:


public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public string Price { get; set; }
    [IgnoreDataMember]
    public int Stock { get; set; }
}

 

  這樣回傳的 JSON 資料就看不到該欄位了,如下:

 

參考資料


Working with OData Queries in ASP.NET Web API

Supported OData Query Options

存取 OData 服務 (WCF Data Services)

將資料公開為 OData 服務 (WCF Data Services)

Queryable 類別

[Web API][OData][筆記] OData初體驗

OData Security Guidance

www.odata.org

Open Data Protocol by Example




以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教
如有侵權內容也請您與我反應~謝謝您 :)