ASP.NET Web API對OData的支持


在SOA的世界中,最重要的一個概念就是契約(contract)。在雲計算的世界中,有關通信的最重要的概念也是契約。XML具有強大對數據的描述能力,Atom格式和AtomPub都建立在XML之上,在Google和微軟的推動下,也已經成為標准。但是,Atom/AtomPub和ODBC/OLEDB這樣的真正數據交互協議相比較,還有着根本上的欠缺:缺乏數據類型的具體描述,降低了交互性能。缺乏對數據查詢的控制能力,比如返回特定的數據集合的區間,或者說分頁能力等等。微軟基於EDM模型釋出了:OData,這里也可以看出Entity Framework對於NHibernate這樣的ORM的工具不同的戰略考慮。

在.NET中,早期是用Remoting/Webservice來處理所有程序間的通信,從.NET 3.0開始使用WCF統一了通信模型,ASP.NET MVC4的推出,形成大的One ASP.NET戰略,增加了WebAPI和SingalR作為通信服務:

oneaspnet

開放數據協議(OData)是一個查詢和更新數據的Web協議。OData應用了web技術如HTTP、Atom發布協議(AtomPub)和JSON等來提供對不同應用程序,服務和存儲的信息訪問。除了提供一些基本的操作(像增刪改查),也提供了一些高級的操作類似過濾數據和實體的導航。OData擴展了上述的協議但是不是取代他們。他可以被XML(ATOM)或者JSON取代但是OData的重要在於它符合REST原則。在某種意義上,它建立在'簡單'的REST HTTP 服務上,並且有着清晰的目標——簡化和標准化我們操作和查詢數據的方式。如果你過去在給你的REST服務創建搜索、過濾、或者分頁API的時候感覺很麻煩,那么OData將是一個不錯的選擇。

目前很多接口,無論是基於SOAP、REST還是別的都在交換數據時使用不同的模式。這種方法隨后返回一大堆客戶記錄。你隨后可以決定添加分頁支持。你希望將結果捆綁在一個網格中,並對數據排序。最后,決定想要查詢的東西,通過比如郵政編碼來查詢。

  首先是,沒有創建泛型客戶端的途徑,而這些和API緊密聯系,因為它不知道參數的順序或者模式被使用的順序。因為不能創建泛型客戶端,你必須為每一個你希望暴露的API創建客戶端。簡單的基礎HTTP API可以實現,但其仍舊很昂貴。逐漸增多的多樣性客戶端與這些API通信加劇了這個問題。

  這種模式的第二個問題是它迫使開發人員進行很艱難的權衡。我應該暴露多少個查詢?你必要在暴露每一個你能想到內容和少暴露一些,從而削弱服務之間協調。前者導致API 需要管理的界面的增加,后者會導致我們通常所說的“數據豎井”,也就是關鍵數據在特定模式中鎖定,其他應用不能夠簡單應用,因為它沒有以一種需要的方式暴露給這個應用。服務試圖比單一應用要獲得更長久一些,因此你需要以一種方式設計API,使其能夠持久,所以如果你發現你需要添加服務借口的新版本可不太好辦,比如創建新的客戶端。在很多案例中,服務開發者和客戶端開發者並不是同一個人,因而改變服務接口簡直就是不可能的事情。

  通過OData,我們采取不同的方法。取代創建客戶端簽名和參數,我們問了如下的問題:“如果你將數據集作為源處理,並為最頻繁使用的操作定義模式,像查詢、分頁、排序、新建、刪除和更新,服務接口因該是什么樣子的?” 這也就導致OData的創建。OData解決了上面提到的關鍵服務設計挑戰。

我們來看一下啟用OData協議的WebAPI的例子:

http://localhost:8080/api/meetings

http://localhost:8080/api/meetings?$filter=(Leader eq ‘Mark Nichols’)

http://localhost:8080/api/meetings?$top=2

http://localhost:8080/api/meetings?$filter=MeetingDate eq datetime’2013-01-17′

在項目中啟用OData查詢,首先在項目加入Web API的OData支持,通過Nuget 查找ASP.NET Web API OData

image

Microsoft.AspNet.WebApi.OData提供可一系列的類擴展了Web API。

在項目中啟用OData查詢:

public static void Register(HttpConfiguration config)
{
    // ...
    config.EnableQuerySupport();
    // ...
}

如果是使用self-hosting方式,在HttpSelfHostConfiguration上啟用EnableQuerySupport():

var config = new HttpSelfHostConfiguration(new Uri("http://localhost:8080"));
config.EnableQuerySupport();

然后將Controls上的Action的返回結果更改為IQueryable,並打上標簽[Queryable()]:

        // GET api/Meeting
        [Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
        public IQueryable<Meeting> Get()
        {
            return _scheduledMeetings.AsQueryable();
        }
需要添加 using System.Web.Http.OData.Query; 我們下AllowedQueryOptions 看支持那些OData的類型:
   // Summary:
    //     OData query options to allow for querying.
    [Flags]
    public enum AllowedQueryOptions
    {
        // Summary:
        //     A value that corresponds to allowing no query options.
        None = 0,
        //
        // Summary:
        //     A value that corresponds to allowing the $filter query option.
        Filter = 1,
        //
        // Summary:
        //     A value that corresponds to allowing the $expand query option.
        Expand = 2,
        //
        // Summary:
        //     A value that corresponds to allowing the $select query option.
        Select = 4,
        //
        // Summary:
        //     A value that corresponds to allowing the $orderby query option.
        OrderBy = 8,
        //
        // Summary:
        //     A value that corresponds to allowing the $top query option.
        Top = 16,
        //
        // Summary:
        //     A value that corresponds to allowing the $skip query option.
        Skip = 32,
        //
        // Summary:
        //     A value that corresponds to allowing the $inlinecount query option.
        InlineCount = 64,
        //
        // Summary:
        //     A value that corresponds to the default query options supported by System.Web.Http.QueryableAttribute.
        Supported = 121,
        //
        // Summary:
        //     A value that corresponds to allowing the $format query option.
        Format = 128,
        //
        // Summary:
        //     A value that corresponds to allowing the $skiptoken query option.
        SkipToken = 256,
        //
        // Summary:
        //     A value that corresponds to allowing all query options.
        All = 511,
    }

上面有個Format,我們可以進行格式化輸出。使用下面的代碼對Format進行數據格式化:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
           

config.Formatters.JsonFormatter.AddQueryStringMapping("$format", "json", "application/json"); config.Formatters.XmlFormatter.AddQueryStringMapping("$format", "xml", "application/xml");

            config.EnableQuerySupport();
        }

另外需要注意的一點是OData查詢是大小寫敏感的。

我將使用Fiddler去測試這個服務

image

image

我們沒有寫任何一個特別的邏輯去支持這些功能,全部都由框架來提供的。是不是OData為你的搜索、過濾、或者分頁API的時候提供了一個很好的選項。

然而,如果要向組織外部公開可查詢的操作,可以利用查詢驗證添加一個保護層以保護我們的服務。微軟的程序經理Hongmei Ge介紹了幾種在Queryable API中添加驗證的場景。

Hongmei指出的第一個場景是,使用AllowedQueryOptions屬性,只允許包含$top和$skip的查詢。如下所示:

[Queryable(AllowedQueryOptions = AllowedQueryOptions.Skip | AllowedQueryOptions.Top)]
public IQueryable Get(int projectId)

還可以使用MaxTop和MaxSkip屬性將$top和$skip的最大值限制在100和200:

[Queryable(MaxTop = 100)]
public IQueryable Get(int projectId)

[Queryable(MaxSkip = 200)]
public IQueryable Get(int projectId)

利用AllowedOrderByProperties,可以將結果按Id屬性排序,因為按其他屬性排序可能會很慢:

[Queryable(AllowedOrderByProperties = "Id")]
public IQueryable Get(int projectId)

如果允許客戶端在$filter內使用相等比較,應該使用AllowedLogicalOperators對其進行驗證:

[Queryable(AllowedLogicalOperators = AllowedLogicalOperators.Equal)]
public IQueryable Get(int projectId)

將AllowedArithmeticOperators設置為None,就可以關閉$filter中的算術操作:

[Queryable(AllowedArithmeticOperators = AllowedArithmeticOperators.None)]
public IQueryable Get(int projectId)

你還可以使用AllowedFunctions屬性來限制$filter中的函數使用:

[Queryable(AllowedFunctions = AllowedFunctions.StartsWith)]
public IQueryable Get(int projectId)

上面的代碼意味着只能在$filter中使用StartsWith函數。

Hongmei還演示了高級場景中的查詢驗證,如為$skip、$top、$orderby、$filter自定義默認驗證邏輯,以及使用ODataQueryOptions來驗證查詢。

相關文章:

OData Developers Reference: http://www.odata.org/developers/

OData in ASP.NET: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api

Limiting OData Query Options: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options

OData Security: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-security-guidance

Add an OData Feed to Your App Using Web API:http://marknic.net/2013/03/02/add-an-odata-feed-to-your-app-using-web-api/

Working with OData Queries in ASP.NET Web API:http://www.codeguru.com/csharp/.net/working-with-odata-queries-in-asp.net-web-api.htm 

在ASP.NET Web API OData中利用Queryable API進行驗證: http://www.infoq.com/cn/news/2013/02/queryable-api

一個創建 OData 的新選項: Web API:http://msdn.microsoft.com/zh-cn/magazine/dn201742.aspx 

Building OData Service using ASP.Net Web API Tutorial – Part 1

示例代碼下載: http://files.cnblogs.com/shanyou/WebApiOData.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM