1. 程式人生 > >OData的初步認識

OData的初步認識

What – OData是什麼?

OData - Open Data Protocol,是一個設計和使用RESTful API的標準。REST本身只是一個構建web服務的思想和理念,其沒有規定一個統一的標準來限制開發人員該如何設計RESTful API。其實我們實際開發中的確也沒有遵循某個統一的標準去設計WebAPI。因為大多數場景下,遵循一個統一的標準並不是必要的。但在某些場景下,有這樣一個標準卻能帶來很大的好處。

OData的理想是, 無論哪個組織構建的RESTful API,只要其符合OData標準。其他組織就可以按照OData標準中定義的方式去使用這個API獲取/修改資源。這個可以類比SQL標準之於RDBMS關係。無論什麼關係型資料庫,如果其聲稱支援SQL 標準,任何人就可以使用標準SQL查詢語句來查詢資料。

標準化的另一個好處:可以將Odata協議實現到一個通用的類庫中,通過這個類庫去建立和訪問RESTful API可以減少開發人員的工作量。官網上有很多這樣的元件。

Who - 誰釋出了OData?

該標準由微軟發起,前三個版本1.0、2.0、3.0都是微軟開放標準。

When - 什麼時候成為了工業標準?

第四個版本4.0於2014年3月17日在OASIS投票通過成為開放工業標準

Why – 為什麼需要OData?

OData是一個協議,一個標準。所以這個問題等同於為什麼我們需要協議。類比TCP協議就可以理解一般。假設你開發的元件必須要和某個第三方元件通訊,如果第三方元件不支援TCP而只支援其內部開發的一個私有協議,你就肯定頭大了,你必須在你的元件裡單獨為其實現這個私有協議。如果大家都支援TCP協議,不就省事了麼。這就是標準協議的作用:協議和標準用於制定一個統一通用的規則。 我們只需要按照這個協議或標準生產元件,那麼這個元件就可以方便的和其他元件整合/協作。而無須根據其他元件的私有標準定製化元件。

前面說到Rest只是一種設計Web服務的思想,不是一種標準化的協議。正由於缺乏標準化,從而導致各家公佈的Restful API 統一通用方面的欠缺。OData就是為彌補這種欠缺而被提出來的標準協議。

下面全是延伸閱讀可略過。

Web服務有兩種實現方式,一是SOAP協議方式,二是REST方式。SOAP是一套完整的實現Web服務的解決方案。這裡有必要先簡單瞭解SOAP方式的Web服務,然後對比SOAP方式,我們會發現REST方式欠缺了什麼。

SOAP方式的Web服務中的Web服務描述語言(WSDL)簡單物件訪問協議(SOAP)一起構成了SOAP方式下的Web服務的結構單元。客戶端通過WSDL可以瞭解Web服務公開了那些可以被執行的方法以及Web服務可以傳送或接收的訊息格式(解決了公佈訪問資源方法的問題)。客戶端按照SOAP將呼叫位於遠端系統上的服務所需資訊序列化為訊息(解決了如何呼叫遠端方法的問題)。注意WSDL描述的服務以及SOAP訊息都是符合統一標準的,都是機器可讀的.

WSDL基於XML格式,用來描述Web服務。WSDL文件可以看成是客戶端和伺服器之間的一個協約。使用WSDL工具,你可以自動處理這個過程,幾乎不用手工編寫程式碼就能夠讓應用程式整合新的服務。因此WSDL是Web服務體系結構的基礎,因為它提供了一個通用語言,用來描述服務和整合這些服務的平臺。

SOAP本身提供了與Web服務交換資訊的方法。SOAP是序列化呼叫位於遠端系統上的服務所需資訊的標準方法,這些資訊可以使用一種遠端系統能夠讀懂的格式通過網路傳送到遠端系統,而不必關心遠端系統運行於何種平臺或者使用何種語言編寫。SOAP以XML格式提供了一個簡單、輕量的用於在分散或分佈環境中交換結構化和型別資訊的機制。實際上它通過提供一個有標準組件的包模型和在模組中編碼資料的機制,定義了一個簡單的表示應用程式語義的機制。

對照SOAP方式的Web服務,REST中沒有用於描述資源(服務)列表,資源元資料的類似於WSDL的東東。所以有人在2009年提出了一個標準WADL去描述REST方式的Web服務,但至今沒有被標準化。個人認為使用WSDL/WADL去描述REST方式的Web服務太彆扭,這是典型的RPC思路,而REST是一種把服務抽象為資源的架構思想。用描述RPC的WSDL去描述REST方式的Web服務並不合適。我們需要其他策略去代替WSDL實現“公佈訪問資源方法的問題”。

由於沒有類似於SOAP的權威性協議作為規範,因此各個網站的REST實現都自有一套,也正是因為這種各自實現的情況,在效能和可用性上會大大高於SOAP釋出的web service,但細節方面有太多沒有約束的地方,其統一通用方面遠遠不及SOAP。

舉個例子:假設A組織,B組織都實現了Restful API來通過工號查詢人員資訊,因為沒有統一的規範。

第三方客戶端在實現遠端呼叫的時候就必須考慮這些API的差異,分別檢視A,B的API文件。

如果有個權威性協議作為規範做指導,規定這個API應該實現成下面這樣,那麼第三方客戶端也只需按照這個標準去呼叫遠端API,而不用檢視A,B的API文件:

解釋了這麼多,就是為了引出:OData是這樣的一個設計和使用Restful API 的權威性協議. OData定義了一些標準規則(像一個介面定義一堆方法一樣),實現Restful API時候,必須實現這些標準規則(就像實現一個介面必須實現其所有方法一樣)。第三方就可以根據Odata協議定義的規則去訪問Restful API。

Where –什麼樣的場景下可以考慮使用OData?

並不是說你建立的所有RESTful API都需要符合OData協議。只有在需要Open Data(開放資料給其他組織)時候,才有必要按照OData協議設計RESTful API。這裡的Open Data是指開放資料給第三方使用,並且你並不知道誰是第三方。比如部落格園的RSS,誰訂閱了RSS,部落格園是不清楚的。如果你的資料只被你自家公司的客戶端使用, OData就是一個可選項,你完全有理由不按照OData規範去設計RESTful API。

How – 如何使用OData?

首先看一下C#客戶端呼叫符合OData標準的WebApi是多麼的方便(官網http://www.odata.org/上也有js的類庫)。

第一步,通過Nuget安裝OData Client for .Net包。

第二步,安裝VS外掛:OData v4 Client Code Generator。

第三步:假設存在一個可用的WebApi(後面介紹如何建立) - http://localhost:33189/Odata. 我們修改程式碼模板中的MetadataDocumentUri如下, 然後儲存。T4會訪問http://localhost:33189/Odata獲得資源的元資料,然後根據元資料生成資源對應的C#類。T4可以怎麼做是因為WebApi是按照OData的標準去公佈資源列表和資源的元資料。

第四步:在我們的程式碼中就可以操作CLR物件來消費遠端的webAPI了。體驗到Odata標準的力量了吧。

接下來看一下C#服務端如何實現上面客戶端需要呼叫的OData的WebAPI,有兩種方式,有點細微的差別。

第一步:建立一個空的WebApi專案。

第二步: 通過Nuget引入EF6 和 WebApi 2.2 for OData v4.0. 如下圖。

第三步:建立Entity和DbContext類,以及配置資料庫連線。並通過enable migration完成資料庫的建立,可在Configuration的seed的方法中,新增一些初始化的資料。

第四步:配置WebApiConfig如下

第五步:建立ProductsController

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using ODataAPI.Models;
using System.Web.OData;

namespace ODataAPI.Controllers
{
    /*
    To add a route for this controller, merge these statements into the Register method of the WebApiConfig class. Note that OData URLs are case sensitive.

    using System.Web.Http.OData.Builder;
    using ODataAPI.Models;
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<Product>("Products");
    config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
    */
    public class ProductsController : ODataController
    {
        private ODataAPIContext db = new ODataAPIContext();

        // GET odata/Products
        //[Queryable]
        [EnableQuery]
        public IQueryable<Product> GetProducts()
        {
            return db.Products;
        }

        // GET odata/Products(5)
        //[Queryable]
        [EnableQuery]
        public SingleResult<Product> GetProduct([FromODataUri] int key)
        {
            return SingleResult.Create(db.Products.Where(product => product.ID == key));
        }

        // PUT odata/Products(5)
        public async Task<IHttpActionResult> Put([FromODataUri] int key, Product product)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (key != product.ID)
            {
                return BadRequest();
            }

            db.Entry(product).State = EntityState.Modified;

            try
            {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ProductExists(key))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return Updated(product);
        }

        // POST odata/Products
        public async Task<IHttpActionResult> Post(Product product)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            db.Products.Add(product);
            await db.SaveChangesAsync();

            return Created(product);
        }

        // PATCH odata/Products(5)
        [AcceptVerbs("PATCH", "MERGE")]
        public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> patch)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Product product = await db.Products.FindAsync(key);
            if (product == null)
            {
                return NotFound();
            }

            patch.Patch(product);

            try
            {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ProductExists(key))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return Updated(product);
        }

        // DELETE odata/Products(5)
        public async Task<IHttpActionResult> Delete([FromODataUri] int key)
        {
            Product product = await db.Products.FindAsync(key);
            if (product == null)
            {
                return NotFound();
            }

            db.Products.Remove(product);
            await db.SaveChangesAsync();

            return StatusCode(HttpStatusCode.NoContent);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool ProductExists(int key)
        {
            return db.Products.Count(e => e.ID == key) > 0;
        }
    }
}
View Code

另外,我們可以通過VS的OData Controller模板來建立webAPIController(如下)。注意使用這種方式建立webAPIController時,不可以匯入WebApi 2.2 for OData v4.0這個類庫,否則會出現dll衝突。

相關推薦

[轉]OData初步認識 OData v4 Client Code Generator

序列 基礎 sta turn out 查詢語句 sql查詢 delete fig 本文轉自:http://www.cnblogs.com/1zhk/p/5356053.html What – OData是什麽? OData - Open Data Proto

OData初步認識

What – OData是什麼? OData - Open Data Protocol,是一個設計和使用RESTful API的標準。REST本身只是一個構建web服務的思想和理念,其沒有規定一個統一的標準來限制開發人員該如何設計RESTful API。其實我們實際開發中的確也沒有遵循某個統一的標準去設計W

lvs初步認識

lvslinux Cluster:Cluster:計算機集合,為解決某個特定問題組合起來形成的單個系統:類型:LB:Load Balancing,負載均衡:HA:High Availiablity ,高可用:HP:High Performance,高性能:分布式系統:分布式存儲分布式計算系統擴展方式:Scal

Ajax的初步認識

無需 這樣的 感受 等待 nbsp rip 取數據 line 接受 在學習php的時候多次看到AjaX的字眼,今日特地上網了解了一下 看來,來日一定會跟它打交道的! 什麽是Ajax Ajax是Asynchronous JavaScript and XML的縮寫,這一

初步認識ASP.NET WebForm

兩個 vs2012 asp 本地ip 管理器 bsp ipc 器) 開發框架 C#可已進行以下兩大類的開發 一.客戶端應用程序C/S 主要有兩種開發技術: 1.winForm windows窗體應用程序 2.WPF微軟新一代圖形框架 MFC(比較老的開發技術) MVVM(客

ZeroMQ 初步認識

details get 消息隊列 war html htm .html mda 隊列 http://www.danieleteti.it/zeromq-for-delphi/ https://my.oschina.net/zeroflamy/blog/109457 ht

對前端語言的初步認識

再次 思維 非阻塞io 事件驅動 特效 strong 而且 語言 情況 web前端,首先不是孤立存在的,前端相對於web後端編程而言,前端是瀏覽器自身支持的編程語言,主要包括html,css,javascript等 HTML: 是構成網頁展示的基礎,主要是復負責頁面的內容顯

初步認識hadoop的一些總結

hadoop<iframe id="embed_dom" name="embed_dom" frameborder="0" style="display:block;width:525px; height:245px;" src="https://www.processon.com/embed/mind

簡單的初步認識Java這門編程語言

java初步認識 java jdk JAVA的誕生:Java於1995年由SUN公司研發推出。Java發展:因為其使用免費,眾多開源插件和類庫,先進的語法面向對象等特性,使得其受到開發人員的喜愛和發展。並且因為其免費開源,有許多的無名工程師、極客在為java進行完善和開發。 Oracle:SUN公

OpenStack入門 之 初步認識

openstack入門 之 初步認識從 OpenStack 基礎知識開始學起,剖析 openstack 架構,分析 OpenStack 的各個組件的功能、原理和使用方法,通過實戰演練來掌握 OpenStack 的部署和操作。為今後學習 OpenStack 的高級課程以及基於 OpenStack 構建企業級雲計

設計模式的初步認識

屬性 eight pat ica nts 第三方類 height 觀察者 橋接 http://blog.csdn.net/zhangerqing/article/details/8194653/ http://www.cnblogs.com/java-my-life/arc

JAVA-初步認識03-第一章命令行

退出 界面 當前 dos window 強制 來源 隨著 小技巧 一.來源 早期計算機的操作是DOS命令行操作,命令行有很多種,這裏說的是windows系統。後來隨著時間的發展,計算機的人機互動從磁盤操作方式變為圖形化操作界面。在這裏我們講述DOS並不是從它早期的起源來的,

JAVA-初步認識01-第一章

必須 全部 其他 數據庫 有序 實現 命令 編輯器 組織 一.目的 首先,我們要討論的是為什麽要學習JAVA?知道了JAVA的定義,也就知道了為什麽學習JAVA。JAVA屬於一種軟件開發工具,那麽學習JAVA就是為了開發軟件。 軟件是將指令和數據有序地的組織在一起,開發軟

JAVA-初步認識-第二章-算術運算符2

字節 如何 原因 最終 ges java 相同 我們 相加 一. 介紹其他類型的運算符。 除了前面介紹的+,-,*,/,%,+連接符外,還有兩種++,--。 二. ++自增 定義:在原有數據的基礎上加一,在賦給原有數據。 對自增運算進行了演示,結果如下:對於++的使用方法還

JAVA-初步認識-第二章-類型運算細節

系統 .com 技術 出錯 計算 兩種 比較 過程 正常 一. 深入探究變量在不同過程中背後隱藏的原理 變量在程序中參與了兩種過程,定義和計算。我們舉一些例子,來說明背後的原理。(除了數值型的變量外,其它類型的也可以是變量,只要一直在變動的就是變量。) 在變量的定義過程中,

JAVA-初步認識-第二章-變量

關鍵字 world 所有 開始 哪些 屬於 數據 類型 class 一. 使用變量的原因 變量可以說是不斷變化的常量,是在常量的基礎上發展而來。比如說“年齡”這個數據,在不同的時候,數值是不一樣的。今年是26,明年是27,但是我們不想在每次提到年齡的時候,都去探尋一下當下歲

JAVA-初步認識-第二章-算術運算符2續

再次 討論 參與 由於 變量 程序 強制 log 自身 一. 對自增運算符的再次認識 首先先明白一點,運算符是運算的符號化表示,每一種運算符的背後都代表著特定的運算。這些運算的形式是各種各樣的,在這裏我們將重新討論自增運算符,符號為++。 對自增運算符進行演示,結果如下:

JAVA-初步認識-第二章-變量的基本演示

變量名 應該 放置 bsp cnblogs 流程 整型 過大 使用 一. 在DOS上演示變量的使用 在JAVA中,變量在使用時有著嚴格地書寫規則:變量類型 變量名 = 初始值;這是對變量進行定義,定義完了之後,就可以使用變量,也就是可以不斷地對變量進行賦值。(在定

JAVA-初步認識-第三章-比較運算符邏輯運算符

表示 font 認識 集中 情況 amp demo .cn 邏輯運算 一. 運算符的總類 先列舉所有的運算符類型:算術運算符,賦值運算符,比較運算符,邏輯運算符,位運算符,三元運算符。 命名為什麽叫運算符,英文叫operator, 難道說這是對操作的符號化表示?可以著一

JAVA-初步認識-第二章-自動類型提升&強制類型轉換

錯誤 http .com com 算術 都是 字符 java 原因 一. 深入理解變量 在之前的講解中,我們談論的都是定義不同類型的變量時要註意的問題。這一節中,我們將變量投入運算,探索在運算過程中,應該遵守的規則。 在這裏對上一節《變量的基本演示》做一個小結,主要有三點。