http://www.cnblogs.com/muyoushui/archive/2013/01/27/2878844.html

ODate 是一种应用层协议,设计它的目的在于提供一组通过HTTP的交互操作。除了提供一些基本的操作(像增删改查),也提供了一些高级的操作类似过滤数据和实体的导航。

下面的文章我将用ODate 提供给ASP.NET Web API 的功能来建立一个小服务。

ODate

你现在可能在想为什么你的web apps需要另外的协议。JSON难道不是很简单吗?XML services 不够好?嗯,事实上,ODate扩展了上述的协议但是不是取代他们。他可以被XML(ATOM)或者JSON取代但是ODate的重要在于它符合REST原则。在某种意义上,它建立在'简单'的REST HTTP 服务上,并且有着清晰的目标——简化和标准化我们操作和查询数据的方式。如果你过去在给你的REST服务创建搜索、过滤、或者分页API的时候感觉很麻烦,那么ODate将是一个不错的选择。

一些ODate查询语法的规则:

  • Entity set – /Artists
  • Entity by id – /Artists(1)
  • Sorting – /Artists?$orderby=Name
  • Filtering – /Artists?$filter=Name eq 'Gridlock'

上面的这些只是冰山一角。

概念介绍的差不多了,让我开始项目吧。很幸运,ASP.NET Web API 可以帮我们很方便的创建ODate。

创建项目

首先我们需要创建一个ASP.NET Web API项目。我们是不需要MVC的相关的东西(视图,js库,等)。

ODate的功能是由一个独立的程序集提供的。请注意,现在这个程序集还是在预览版,最新的官方发布版本是0.3 RC (this blogpost 点击链接参看项目信息,这个是英文的哦)。

很不幸,使用最新的ODataLib程序集还有一些方法(例如:过滤)没有实现,不过不用担心最新的更新将会解决这个问题。因为没有必要学习过时的API,我们将使用最新的发布版本在http://www.myget.org/F/aspnetwebstacknightly/,使用nuget。如果你不会使用nuget,可以看看这里here

一旦你获取了nightly build nuget source。可以使用Manage NuGet Packages安装最新的Web API OData 包,确保你选择'Include Prerelease'在上面的下拉框中,如下图所示。

另外需要注意的是Web API OData 还在开发阶段,还有一些功能还不支持。不过基本功能已经完成。

数据模型

我们需要一些简单的模型去操作,使用Entity Framework 和 SQL CE 4,但是Web API's OData也支持其他的数据库和持久化技术。

CREATE TABLE [Album]
(
[AlbumId] INT NOT NULL IDENTITY,
[Title] NVARCHAR(160) NOT NULL,
[ArtistId] INT NOT NULL,
[GenreId] INT NOT NULL,
[ReleaseDate] DATETIME,
CONSTRAINT [PK_Album] PRIMARY KEY ([AlbumId])
); CREATE TABLE [Artist]
(
[ArtistId] INT NOT NULL IDENTITY,
[Name] NVARCHAR(120),
CONSTRAINT [PK_Artist] PRIMARY KEY ([ArtistId])
); CREATE TABLE [Genre]
(
[GenreId] INT NOT NULL IDENTITY,
[Name] NVARCHAR(120),
[Description] NVARCHAR(1020),
CONSTRAINT [PK_Genre] PRIMARY KEY ([GenreId])
); ALTER TABLE [Album] ADD CONSTRAINT [FK_AlbumArtistId]
FOREIGN KEY ([ArtistId]) REFERENCES [Artist] ([ArtistId])
ON DELETE NO ACTION ON UPDATE NO ACTION; CREATE INDEX [IFK_AlbumArtistId] ON [Album] ([ArtistId]); ALTER TABLE [Album] ADD CONSTRAINT [FK_AlbumGenreId]
FOREIGN KEY ([GenreId]) REFERENCES [Genre] ([GenreId])
ON DELETE NO ACTION ON UPDATE NO ACTION; CREATE INDEX [IFK_AlbumGenreId] ON [Album] ([GenreId]);

你可以创建一个新的SQL CE数据库在App_Data文件夹下面,使用内置的环境去执行SQL代码。请注意执行SQL只能一行一行执行,不支持一下子执行多次语句。一旦数据库表结构完成了我们可以用VS2012向导生成Entity Data Model。

最后我们将得到一个DbContext类去进行数据操作。

$metadata endpoint 和 IEdmModel

正如我之前提到的,ODate标准定义了一个特别的metadata endpoint,它包含一个定义了实体集,关系,实体类型和操作的文档。这些保证了ODate是自描述的,能够让客户端去生成表示服务端类型的客户端代码,简化了服务的访问方式。Metadata endpoint应该在/$metadata下可用。如果你熟悉SOAP服务,你可以把ODate和它类比一下。

GET http://services.odata.org/Northwind/Northwind.svc/$metadata

Metadata文档使用ODate通用架构定义(OData Common Schema Definition Language (CSDL))。很幸运,ASP.NET Web API可以把$metadata endpoint直接暴露给我们,只要我们的模型继承IEdmModel

public class ModelBuilder
{
public IEdmModel Build()
{
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Album>("Albums");
modelBuilder.EntitySet<Artist>("Artists");
modelBuilder.EntitySet<Genre>("Genres"); return modelBuilder.GetEdmModel();
}
}
public IEdmModel BuildExplicitly()
{
ODataModelBuilder modelBuilder = new ODataModelBuilder();
EntitySetConfiguration<Genre> genres = modelBuilder.EntitySet<Genre>("Genres");
EntityTypeConfiguration<Genre> genre = genres.EntityType;
genre.HasKey(g => g.GenreId);
genre.Property(g => g.Name);
genre.Property(g => g.Description); //(...) return modelBuilder.GetEdmModel();
}

使用ODate

Microsoft.AspNet.WebApi.OData提供可一系列的类扩展了Web API

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var modelBuilder = new ModelBuilder();
IEdmModel model = modelBuilder.Build();
config.Routes.MapODataRoute("OData", null, model);
config.EnableQuerySupport();
}
}

这些代码(Global.asax.cs)做了两件事情:

  1. 通过路由注册我们的模型表示方法-
  2. 使查询可用

现在我们的服务应该自动知道怎么去处理OData ~/$metadata 请求。很酷,不是吗? 

<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" Version="1.0">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0">
<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" Namespace="Piotr.ODataWebApiService.Service.Models">
<EntityType Name="Album">...</EntityType>
<EntityType Name="Artist">...</EntityType>
<EntityType Name="Genre">...</EntityType>
<Association
Name="Piotr_ODataWebApiService_Service_Models_Album_Artist_Piotr_ODataWebApiService_Service_Models_Artist_ArtistPartner">...</Association>
<Association Name="Piotr_ODataWebApiService_Service_Models_Album_Genre_Piotr_ODataWebApiService_Service_Models_Genre_GenrePartner">...</Association>
<Association Name="Piotr_ODataWebApiService_Service_Models_Artist_Albums_Piotr_ODataWebApiService_Service_Models_Album_AlbumsPartner">...</Association>
<Association Name="Piotr_ODataWebApiService_Service_Models_Genre_Albums_Piotr_ODataWebApiService_Service_Models_Album_AlbumsPartner">...</Association>
</Schema>
<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" Namespace="Default">...</Schema>
</edmx:DataServices>
</edmx:Edmx>

控制器

现在是时候去检测一下我们的成果了。我们应该添加一个暴露ODate资源的控制器。正如你将看到的,这和一个平常的CRUD控制器很不一样。暴露一个ODate实体非常容易。

[ODataRouting]
[ODataFormatting]
public class ArtistsController : ApiController
{
private AlbumsContext db = new AlbumsContext(); // GET /Artists
// GET /Artists?$filter=startswith(Name,'Grid')
[Queryable]
public IQueryable<Artist> Get()
{
return db.Artists;
} protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
[ODataRouting]
[ODataFormatting]
public class ArtistsController : ApiController
{
private AlbumsContext _db = new AlbumsContext(); // GET /Artists
// GET /Artists?$filter=startswith(Name,'Grid')
[Queryable]
public IQueryable<Artist> Get()
{
return _db.Artists;
} // GET /Artists(2)
public HttpResponseMessage Get([FromODataUri]int id)
{
Artist artist = _db.Artists.SingleOrDefault(b => b.ArtistId == id);
if (artist == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
} return Request.CreateResponse(HttpStatusCode.OK, artist);
} public HttpResponseMessage Put([FromODataUri] int id, Artist artist)
{
if (!_db.Artists.Any(a => a.ArtistId == id))
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
//overwrite any existing id, as url is more explicit
artist.ArtistId = id;
_db.Entry(artist).State = EntityState.Modified; try
{
_db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
} return Request.CreateResponse(HttpStatusCode.NoContent);
} public HttpResponseMessage Post(Artist artist)
{
var odataPath = Request.GetODataPath();
if (odataPath == null)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest,
"ODataPath not present in the request.");
} var entitySetPathSegment
= odataPath.Segments.FirstOrDefault() as EntitySetPathSegment; if (entitySetPathSegment == null)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest,
"ODataPath does not start with entity set path segment");
} Artist addedArtist = _db.Artists.Add(artist);
_db.SaveChanges();
var response = Request
.CreateResponse(HttpStatusCode.Created, addedArtist); response.Headers.Location = new Uri(Url.ODataLink(
entitySetPathSegment,
new KeyValuePathSegment(ODataUriUtils
.ConvertToUriLiteral(addedArtist.ArtistId
, ODataVersion.V3))));
return response;
} public HttpResponseMessage Patch([FromODataUri] int id,
Delta<Artist> artistPatch)
{
Artist artist = _db.Artists
.SingleOrDefault(p => p.ArtistId == id);
if (artist == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
} artistPatch.Patch(artist);
_db.SaveChanges(); return Request.CreateResponse(HttpStatusCode.NoContent);
} public HttpResponseMessage Delete([FromODataUri] int id)
{
Artist artist = _db.Artists.Find(id);
if (artist == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
} _db.Artists.Remove(artist); _db.SaveChanges();
return Request.CreateResponse(HttpStatusCode.Accepted);
} protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
}

测试这个服务

我将使用Fiddler去测试这个服务。

注意 Content-Type: application/json这个头。应该加一个新的类型。如果我们想要更新实体的一部分,如下图

现在这个类别为id=3将更新描述。

最后,我们进行一个文章实体排序操作如下图,http://localhost:2537/Artists?$orderby=Name&$inlinecount=allpages

正如你以上看到的,我们没有写任何一个特别的逻辑去支持这些功能,全部都由框架来提供的,当然如果你愿意,也可以自己写控制器不限于ODate指定的CRUD操作。

ODate毫无疑问是一个有趣的协议。我感觉它更像一个加强的REST服务。

本文的源代码在bitbucket

译后语:

原文地址:http://www.piotrwalat.net/getting-started-with-odata-services-in-asp-net-web-api/

OData services作为一种最新的协议,将来可能会大规模使用,可能就没有未来。但是关注一点新的技术总没什么害处吧,万一以后你的公司用了,你可以说一句"貌似我以前看过一点",与时俱进嘛。

翻译中遇到的一些好玩,好用的句型:

a tip of an iceberg冰山一角

reap the reward 获得奖励

on steroids 加强的,这个单词词典的翻译是"类固醇",太坑爹,这里完全不是这个意思,后来看了很多例句才体会出加强这个意思。

-------------------------------------------------

!!!作者:木由水 http://www.cnblogs.com/muyoushui

OData services入门----使用ASP.NET Web API描述的更多相关文章

  1. [转]Supporting OData Query Options in ASP.NET Web API 2

    本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/suppor ...

  2. Web API 2 入门——使用ASP.NET Web API和Angular.js构建单页应用程序(SPA)(谷歌翻译)

    在这篇文章中 概观 演习 概要 由网络营 下载网络营训练包 在传统的Web应用程序中,客户机(浏览器)通过请求页面启动与服务器的通信.然后,服务器处理请求,并将页面的HTML发送给客户端.在与页面的后 ...

  3. Create an OData v4 Endpoint Using ASP.NET Web API 2.2(使用ASP.NET Web API 2.2创建OData v4端点)

    开放数据协议Open Data Protocol(OData)是web的一种数据存取协议,OData通过设置CRUD操作(Create创建.Read读取.Update更新,Delete删除)提供一种统 ...

  4. Web API 2 入门——创建ASP.NET Web API的帮助页面(谷歌翻译)

    在这篇文章中 创建API帮助页面 将帮助页面添加到现有项目 添加API文档 在敞篷下 下一步 作者:Mike Wasson 创建Web API时,创建帮助页面通常很有用,以便其他开发人员知道如何调用A ...

  5. 杂项:ASP.NET Web API

    ylbtech-杂项:ASP.NET Web API ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务. ASP.NET Web A ...

  6. [转]Web API Introduction to OData Services using ASP.NET Web API

    本文转自:http://mahedee.net/tag/web-api/ What is OData? OData Stands for Open Data Protocol. It is a dat ...

  7. 水果项目第3集-asp.net web api开发入门

    app后台开发,可以用asp.net webservice技术. 也有一种重量级一点的叫WCF,也可以用来做app后台开发. 现在可以用asp.net web api来开发app后台. Asp.net ...

  8. 【ASP.NET Web API教程】1 ASP.NET Web API入门

    原文 [ASP.NET Web API教程]1 ASP.NET Web API入门 Getting Started with ASP.NET Web API第1章 ASP.NET Web API入门 ...

  9. 对一个前端AngularJS,后端OData,ASP.NET Web API案例的理解

    依然chsakell,他写了一篇前端AngularJS,后端OData,ASP.NET Web API的Demo,关于OData在ASP.NET Web API中的正删改查没有什么特别之处,但在前端调 ...

随机推荐

  1. Threads Events QObjects

    Events and the event loop Being an event-driven toolkit, events and event delivery play a central ro ...

  2. ld链接问题解决

    http://stackoverflow.com/questions/480764/linux-error-while-loading-shared-libraries-cannot-open-sha ...

  3. 为AM335x移植Linux内核主线代码

    /********************************************************************** * 为AM335x移植Linux内核主线代码 * 说明: ...

  4. Linux服务器使用命令操作MySQL插入数据乱码问题

    服务器上使用MySQL命令方式进行插入数据时,很多时候会遇到插入数据乱码问题,导出一个sql执行文件,再倒入到unbutn中,结果出现乱码,折腾7-8分钟, 解决方式 在导出mysql sql执行文件 ...

  5. Why did Jimmy Wales invest in Quora? Is he afraid that it will take over Wikipedia?

    QUESTION: Why did Jimmy Wales invest in Quora? Is he afraid that it will take over Wikipedia? Answer ...

  6. Matlab 矩阵卷积理解(转载)

    转载自:http://blog.csdn.net/andrewseu/article/details/51783181 在图像处理的过程中,经常会看到矩阵卷积的概念,比如说用一个模板去和一张图片进行卷 ...

  7. Codeforces Round #285 (Div. 2) A B C 模拟 stl 拓扑排序

    A. Contest time limit per test 1 second memory limit per test 256 megabytes input standard input out ...

  8. CDH hive的安装

    tar zxvf 解压包 配置环境变量 export HIVE_HOME=/usr/local/soft/hiveexport PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HO ...

  9. SysTick 定时器的使用

    SysTick是STM32中的一个24位的定时器. Cortex‐M3处理器内部包含了一个简单的定时器.因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简.该定时器的时钟 ...

  10. [hdu 4416]Good Article Good sentence

    最近几天一直在做有关后缀自动机的题目 感觉似乎对后缀自动机越来越了解了呢!喵~ 这题还是让我受益颇多的,首先搞一个后缀自动机是妥妥的了 可是搞完之后呢? 我们来观察 step 这个变量,每个节点的 s ...