程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> [水煮 ASP.NET Web API2 方法論](12-1)創建 OData,api2odata

[水煮 ASP.NET Web API2 方法論](12-1)創建 OData,api2odata

編輯:關於.NET

[水煮 ASP.NET Web API2 方法論](12-1)創建 OData,api2odata


問題

  怎樣用在 Web API 中創建 OData 服務。

 

解決方案

  對於我們來說,在 Web API 中使用 OData最簡單的方式就是使用 ASP.NET 模板來創建Odata Controller。在 Controllers 文件夾上鼠標右鍵->添加->新建項。

wKiom1glDKCzoR0BAAEYtJ6ZIOQ942.png

 

  顯示一個如圖 12-1 的對話框,在這裡我們可以選擇兩個 “Web API 2 OData” 相關的模板。Vistual Studio將會生成相關的 OData Controller,同時,從 NuGet 上下載 OData 需要的所有程序集。

圖 12-1. 使用模板添加 OData Controller

wKioL1glDMaxZzIIAAC5fDASuZ4568.png

 

  不過,這個模板僅僅對於 WEB Host (ASP.NET Web API 托管在 ASP.NET Web 應用程序中)是可以用。對於 Web API 托管在其他地方,我們可以通過 NuGet 手動安裝 OData Microsoft.AspNet.OData 來開啟我們的OData 開發之旅。

 

工作原理

  OData 是一種通過 HTTP 公開豐富 API的標准化協議。OData 4.0 已經被 OASIS 國際開放標准聯盟批准,也被認為是 Web 界的 ODBC。

 

Open Data Protocol(OData )可以創建基於REST 的數據服務,可以是資源,使用 URL 和定義的數據模型,可以通過 Web 客戶端使用簡單的 HTTP 消息來發布和編輯。

 OData 4.0

http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part1-protocol.html

 

小提示 OData 主頁 www.odata.org 裡面有所有感興趣的資源,他可以幫助我們了解 Odato 協議。

ASP.NET WWB API 2.2 支持 OData 4.0(Microsoft.AspNet.OData NuGet 包),然而,之前的 Web API 支持的OData 3.0。如果我們要是指定引用 Mircosoft.Aspnet.WebApi.OData NuGet 包,還是可以使用 OData 3.0。

OData Controller 應該繼承自 ODataController 基類,而不是常規的ApiController。ASP.NET Web API 允許我們在一個項目中混合使用 OData 的Controller 和 傳統的 Controller,所以,我們可以在提供 OData Api 的同時提供常規 Api。

Controller 繼承 ODataController 是有框架進行不同配置的。被稱為 ODataActionSelector 的 Odata IHttpAcionSelector 的實現類,是基於 Odata 路由的約定,以及一組特定的媒體類型格式化也是被默認替換的。所有的 OData 格式化程序都是 ODataMediaTypeFormatter 的變種,他可以處理 OData 指定的請求和相應格式,XML 和 JSON。

 

代碼演示

  清單 12-1 展示了一個完成的功能,而且很典型的 ODataController 的 CRUD。在這樣的情況下,會通過ASP.NET 的模板根據 Player 實體和 EF 數據上下文生成 Controller。

 

清單 12-1 典型的 ODataController

1 2 3 4 5 6 7 8 9 namespace BoiledCode.WebApi.Recipe.ODataDemo.Models {     public class Player     {         public int Id { getset; }         public string Name { getset; }         public string Team { getset; }     } }

 

wKioL1glDN-jaix-AAAmSQFySzs693.png-wh_50

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 using System.Data.Entity.Infrastructure; using System.Linq; using System.Net; using System.Web.Http; using System.Web.OData; using BoiledCode.WebApi.Recipe.ODataDemo.Models;    namespace BoiledCode.WebApi.Recipe.ODataDemo.Controllers {     /*     The WebApiConfig class may require additional changes to add a route for this controller. Merge these statements into the Register method of the WebApiConfig class as applicable. Note that OData URLs are case sensitive.        using System.Web.OData.Builder;     using System.Web.OData.Extensions;     using BoiledCode.WebApi.Recipe.ODataDemo.Models;     ODataConventionModelBuilder builder = new ODataConventionModelBuilder();     builder.EntitySet<Player>("Players");     config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());     */        public class PlayersController : ODataController     {         private readonly ApplicationDbContext db = new ApplicationDbContext();            // GET: odata/Players         [EnableQuery]         public IQueryable<Player> GetPlayers()         {             return db.Players;         }            // GET: odata/Players(5)         [EnableQuery]         public SingleResult<Player> GetPlayer([FromODataUri] int key)         {             return SingleResult.Create(db.Players.Where(player => player.Id == key));         }            // PUT: odata/Players(5)         public IHttpActionResult Put([FromODataUri] int key, Delta<Player> patch)         {             Validate(patch.GetEntity());                if (!ModelState.IsValid)             {                 return BadRequest(ModelState);             }                var player = db.Players.Find(key);             if (player == null)             {                 return NotFound();             }                patch.Put(player);                try             {                 db.SaveChanges();             }             catch (DbUpdateConcurrencyException)             {                 if (!PlayerExists(key))                 {                     return NotFound();                 }                 throw;             }                return Updated(player);         }            // POST: odata/Players         public IHttpActionResult Post(Player player)         {             if (!ModelState.IsValid)             {                 return BadRequest(ModelState);             }                db.Players.Add(player);             db.SaveChanges();                return Created(player);         }            // PATCH: odata/Players(5)         [AcceptVerbs("PATCH""MERGE")]         public IHttpActionResult Patch([FromODataUri] int key, Delta<Player> patch)         {             Validate(patch.GetEntity());                if (!ModelState.IsValid)             {                 return BadRequest(ModelState);             }                var player = db.Players.Find(key);             if (player == null)             {                 return NotFound();             }                patch.Patch(player);                try             {                 db.SaveChanges();             }             catch (DbUpdateConcurrencyException)             {                 if (!PlayerExists(key))                 {                     return NotFound();                 }                 throw;             }                return Updated(player);         }            // DELETE: odata/Players(5)         public IHttpActionResult Delete([FromODataUri] int key)         {             var player = db.Players.Find(key);             if (player == null)             {                 return NotFound();             }                db.Players.Remove(player);             db.SaveChanges();                return StatusCode(HttpStatusCode.NoContent);         }            protected override void Dispose(bool disposing)         {             if (disposing)             {                 db.Dispose();             }             base.Dispose(disposing);         }            private bool PlayerExists(int key)         {             return db.Players.Count(e => e.Id == key) > 0;         }     } }

 

這個控制器和正常的 Controller 非常相似,只有幾個地方是需要強調

  • OData 查詢語法是通過     EnableQueryAttribute 來啟用的。我們將在 12-3 來繼續討論。

  • OData 查詢語法不僅可以用在集合上也可以用在單個實體上,用在單個實體上的時候,只要實體使用  SingleResult<T> 就可以。關於這個我們也是在 12-3 來詳細介紹。

  • 從 URI 綁定的時候,需要使用     FromODataUriAttribute,而不是傳統的 Web API FormUriAttribute。

  • OData Controller 一般是允許部分實體的更新。這個例子上,是通過 HTTP 的 PATCH 和 Delta<T>來實現部分更新。Delta<T> 是一種特殊的類型,可以用於比較兩個實體之間的差異,但是,他僅僅適用於     ODataMediaTypeFormatters 類型。

  很顯然,控制器並非萬能的。使用 OData 的最小要求就是為OData 創建一個實體數據模型(EDM)和 設置OData 路由。這些最終操作的都是 Web API HttpConfiguration 的實例。如清單 12-2 所示,我們會在下一次(12-2)來介紹 OData 路由。EDM 是用來為我們的服務定義 URI,以及提供語義描述(元數據)。

 

清單 12-1. 設置 EDM 和 OData 路由

1 2 3 4 5 6 7 8 9 10         public void SettingUpEdmRoyte()         {             var config = new HttpConfiguration();             //配置 Web API             var builder = new ODataConventionModelBuilder();             builder.EntitySet<Player>("Players");             // 第一個參數:路由名稱,第二個參數:OData 路由前綴             // players 資源可以被 /odata/players 訪問             config.MapODataServiceRoute("odata""odata", builder.GetEdmModel());         }

 

  這個 ODataConventionModelBuilder 類可以幫我們創建一個 EDM,我們不需要不必擔心名稱轉換,導航屬性,主鍵。如果我們需要自定義這些默認關系,那麼,我們就需要使用它的基類 ODataModelBuilder,而不是ODataConventionModelBuilder。

  EntitySet方法添加實體並設置為 EDM 同時定義指定的 ODataController 來處理相應資源的 HTTP 請求,在我們的例子中就是 PlayersController。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved