ASP.NET Web API 2 OData v4教程
創建項目
在VS中創建一個新的Asp.Net Web應用項目,命名為“PersonsService”,如下圖:
安裝Nuet包
搜索Microsoft.AspNet.Odata包跟EntityFramework包安裝
添加Model類
Model類是一個表示應用中的數據實體的對象。
在解決方案資源管理器中的Models文件夾下,創建一個Person類:
namespace PersonsService.Models { public class Person { public int Id { get; set; } public string Name { get; set; } public bool Gender { get; set; } public string UserName { get; set; } } }
生成數據庫
打開Web.config文件,在configuration元素中添加下面的connectionStrings節點:
<connectionStrings> <add name="PersonsContext" connectionString="Server=.;Database=PersonsDB;Integrated Security=True" providerName="System.Data.SqlClient"/> </connectionStrings>
在Models文件夾下添加一個PersonsContext類:
using System.Data.Entity; namespace PersonsService.Models { public class PersonsContext : DbContext { public PersonsContext() : base("name=PersonsContext") { } public DbSet<Person> Persons { get; set; } } }
打開NuGet包管理器,程序包管理器控制臺輸入以下命令 "enable-migrations" ,"add-migration","update-database "
這個時候打開SQL Server 就可以看到已經創建好的數據庫
配置OData終結點
打開App_Start/WebApiConfig.cs文件,配置下面的新代碼
using Microsoft.OData.Edm; using PersonsService.Models; using System.Web.Http; using System.Web.OData.Builder; using System.Web.OData.Extensions; namespace PersonsService { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); //構建路由服務 config.MapODataServiceRoute( routeName: "odata", routePrefix: "odata", model: GetModel() ); } private static IEdmModel GetModel() { var builder = new ODataConventionModelBuilder(); var esPerson = builder.EntitySet<Person>("Persons"); return builder.GetEdmModel(); } } }
上面的代碼做了兩件事:
- 創建了一個實體數據模型(Entity Data Model【簡稱EDM】)。
- 添加了一個路由。
EDM是一個抽象的數據模型。EDM用於創建服務元數據文檔。ODataConventionModelBuilder類使用默認的命名規範創建了一個EDM。這種方式需要寫的代碼最少。如果你想更多地控制EDM,那麽你可以使用 ODataModelBuilder類來創建EDM類,這樣做就要顯式添加屬性,鍵和導航屬性。
路由(route)會告訴Web API如何將HTTP請求路由到終結點。調用MapODataServiceRoute 擴展方法可以創建一個OData v4路由。
如果你的應用有了多個OData終結點,那麽要為每個終結點創建一個單獨的路由,給每個路由一個唯一的路由名和前綴(prefix)。
添加OData控制器
控制器是處理HTTP請求的一個類。在OData應用中,應該為每個實體集創建一個單獨的控制器。而在這篇博客中,我們只要為Person實體創建一個控制器就行了。
在Controllers文件夾下添加一個控制器,如下:
修改控制器代碼,如下:
using PersonsService.Models; using System.Linq; using System.Web.OData; namespace PersonsService.Controllers { public class PersonsController : ODataController { private readonly PersonsContext db = new PersonsContext(); [EnableQuery] public IQueryable<Person> Get() { return db.Persons; } [EnableQuery] public IQueryable<Person> Get([FromODataUri] int key) { return db.Persons.Where(r=> r.Id==key); } } }
這時我們手動給數據庫添加些數據,
好了,現在我們運行項目嘗試請求下
請求http://localhost:3370/odata/Persons
現在數據都出來了,試下請求單個Person
http://localhost:3370/odata/Persons(1)
一切正常
無參數的Get()方法會返回整個Person表的集合。
Get([FromODataUri] int key)方法會返回指定Id的Person。
[EnableQuery]特性允許客戶端使用查詢選項(如$filter,$sort和$page)修改查詢。
添加一個Post方法來添加Person
[HttpPost] public IHttpActionResult Post(Person person) { if (!ModelState.IsValid) { return BadRequest(ModelState); } db.Persons.Add(person); db.SaveChanges(); return Created(person); }
使用post請求http://localhost:3370/odata/Persons
看下數據庫趙六已經添加進去了,現在添加一個修改方法
OData支持兩種不同語義更新實體,包括PATCH和PUT。
- PATCH執行一個部分更新,客戶端只識別要更新的屬性。
- PUT會替換整個實體。
PUT的劣勢在於客戶端必須發送實體的所有屬性,包括沒有改變的值。
OData說明書陳述了PATCH是首選。
[AcceptVerbs("PATCH", "MERGE")] public IHttpActionResult Patch([FromODataUri] int key, Delta<Person> patch) { if (!ModelState.IsValid) { return BadRequest(ModelState); } Person person = db.Persons.Find(key); if (person == null) { return NotFound(); } patch.Patch(person); try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { throw; } return Updated(person); }
在PATCH中,控制器使用了Delta類型來跟蹤改變。
刪除實體
允許客戶端從數據庫刪除一個Person:
// DELETE: odata/Persons(5) public IHttpActionResult Delete([FromODataUri] int key) { Person person = db.Persons.Find(key); if (person == null) { return NotFound(); } db.Persons.Remove(person); db.SaveChanges(); return StatusCode(HttpStatusCode.NoContent); }
後續會補充下odata配置自定義路由的問題.
Odata 自定義路由
[EnableQuery, HttpGet] [ODataRoute("Products({id})/Default.GetCatAndTown")] public IHttpActionResult GetCatAndTown([FromODataUri] int id) { var list = db.Products.Where(r => r.Id == id); return Ok(list); }
當然這個時候我們請求http://localhost:6785//Odata/Products(1)/Default.GetCatAndTown會報錯404,解決方案是添加一個尾部的斜杠到請求的網址
這個時候我們http://localhost:6785//Odata/Products(1)/Default.GetCatAndTown/就會好了,具體原因不詳。或者是修改web.config文件
<system.webServer> <handlers> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> <add name="ExtensionlessUrlHandler-Integrated-4.0Custom" path="/odata*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> </handlers> </system.webServer>
ASP.NET Web API 2 OData v4教程