Creating a REST service using ASP.NET Web API

A service that is created based upon the architecture of REST is called as REST service. Although REST looks more inclined to web and HTTP its principles can be applied to other distributed communication systems also. One of the real implementation of REST architecture is the World Wide Web (WWW). REST based services are easy to create and can be consumed from a wide variety of devices.

REST (REpresentational State Transfer,表述性状态转移) 。REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。

REST 定义了一组体系架构原则,您可以根据这些原则设计以系统资源为中心的 Web 服务,包括使用不同语言编写的客户端如何通过 HTTP 处理和传输资源状态。 如果考虑使用它的 Web 服务的数量,REST 近年来已经成为最主要的 Web 服务设计模式。 事实上,REST 对 Web 的影响非常大,由于其使用相当方便,已经普遍地取代了基于 SOAP 和 WSDL 的接口设计。

There are many APIs available in different languages to create and consume REST services. The ASP.NET MVC beta 4 comes with a new API called ASP.NET Web API to create and consume REST services. While creating REST services it is important to follow the rules and standards of the protocol (HTTP). Without knowing the principles of REST it is easy to create a service that looks RESTful but they are ultimately an RPC style service or a SOAP-REST hybrid service. In this article we are going to see how to create a simple REST service using the ASP.NET Web API.

ASP.NET MVC beta 4附带了API开发功能,同时可以调用ASP.NET Web API来创建和使用 REST 服务。创建其他服务时很重要的是要遵循标准的协议 (HTTP)。

在这篇文章我们来看看如何创建一个简单的ASP.NET Web API REST服务,并且调用它。

开发工具:Visual Studio 2013

创建步骤:

1. 模型化数据

创建一个新的ASP.NET WEB项目,在如下图界面选择Empty模板并且勾上Web API选项。(这里我们不使用Asp.net Mvc4的方式去创建,我认为应该采用独立的方式去创建比较好)

然后再Model中创建一个类Person:

public class Person

 { 

public int Id { get; set; } 

public string FirstName { get; set; } 

public string LastName { get; set; } 

}

在这里您可能会在您认为合理的框架中使用Web API,所以我们只从原理上来描述它,不拘泥于具体的实现方式和设计模式。

接着在Model中创建一个接口IPersonRepository

public interface IPersonRepository

 { 

IEnumerable<Person> GetAll(); 

Person Get(int id); 

Person Add(Person person); 

void Remove(int id); 

bool Update(Person person); 

 }

然后,让我们去实现它。同样在Model中创建一个实现类PersonRepository

    public class PersonRepository : IPersonRepository
{ private List<Person> _people = new List<Person>();
private int num = 1; public PersonRepository()
{
this.Add(new Person { LastName = "三", FirstName = "张" });
this.Add(new Person { LastName = "四", FirstName = "李" });
this.Add(new Person { LastName = "五", FirstName = "王" });
this.Add(new Person { LastName = "六", FirstName = "老" });
} public IEnumerable<Person> GetAll()
{
return _people;
} public Person Get(int id)
{
return _people.Find(p => p.Id == id);
} public Person Add(Person person)
{
if (person == null)
throw new ArgumentNullException("person");
person.Id = num++;
_people.Add(person);
return person;
} public void Remove(int id)
{
_people.RemoveAll(p => p.Id == id);
} public bool Update(Person person)
{
if (person == null)
throw new ArgumentNullException("person"); int index = _people.FindIndex(p => p.Id == person.Id);
if (index == -1)
return false;
_people.RemoveAt(index);
_people.Add(person);
return true;
}
}

在这个实现中不管您将采取任何数据来源XML,文件或者其他持久化存储,我们都可以返回一个实现了IEnumerable接口的列表,从而消除数据来源的差异性。

2. 使用Api Controllers 访问 API 服务

Unlike an ASP.NET/MVC Project, which generally uses Controllers derived from System.Web.MVC.Controller, a WebApi project will generally utilize controllers derived from System.Web.Http.WebApiController. Like the standard MVC Controller, The WebApi Controller accepts incoming HTTP requests and processes accordingly. However, the standard MVC Controller returns a View, while the WebApi controller returns data.

特别值得注意的是,WebApi controller会检查接受HTTP请求头部。然后将NET对象序列化为适当的返回数据类型(XML或JSON)。

在Controllers文件夹上右键选择添加—>控制器,然后如下图选择

命名为PersonController。

现在您可以方便的在这里添加任何GURD代码。我们一起来分析一个具体实现:

static readonly IPersonRepository databasePlaceholder = new PersonRepository(); 

public Person GetPersonByID(int id) 

 { 

Person person = databasePlaceholder.Get(id); 

if (person == null) 

 { 

//返回一个自定义HTTP状态码

throw new HttpResponseException(HttpStatusCode.NotFound); 

 } 

return person; 

 }

第一句代码可以说是实例化一个数据访问类,而我们要做的是根据ID返回要查询的Person对象,通过调用对应方法可以实现。注意观察这个方法是以Get方式开头,而这个方法包含一个id参数,这个方法会匹配/api/PersonController/id的请求,而请求中的参数id会自动转换为int类型

如果没有找到相应id的联系人,则会抛出一个自定义HttpResponseMessage的异常,这个异常是指向的404异常,表示请求资源不存在。实际项目中,我们是非常有必要返回一些和操作对应的异常信息的。

完整代码如:

    public class PersonController : ApiController
{
static readonly IPersonRepository databasePlaceholder = new PersonRepository(); public Person GetPersonByID(int id)
{
Person person = databasePlaceholder.Get(id);
if (person == null)
{
//返回一个自定义HTTP状态码
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return person;
} public IEnumerable<Person> GetAllPeople()
{
return databasePlaceholder.GetAll();
} public HttpResponseMessage PostPerson(Person person)
{
person = databasePlaceholder.Add(person);
var response = this.Request.CreateResponse<Person>(HttpStatusCode.Created, person);
string uri = Url.Link("Default", new { id = person.Id });
response.Headers.Location = new Uri(uri);
return response;
} public bool PutPerson(Person person)
{
if (!databasePlaceholder.Update(person))
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return true;
} public void DeletePerson(int id)
{
Person person = databasePlaceholder.Get(id);
if (person == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
databasePlaceholder.Remove(id);
}
}
As we have alluded to previously, a core tenet of MVC is to favor Convention over Configuration. In terms of our controller class, what this means is that the ASP.NET/MVC runtime establishes certain default behaviors which require no additional configuration, unless you want to change them. Initially, for me anyway, this was also a source of confusion, as the runtime appeared to perform sufficient "magic" that I didn't know what was happening.

当然其中一个非常重要的Web API规范就是HTTP谓词的映射,如GET、POST、PUT、DELETE。那么正如我们上面所述,我们的动作也遵循了这个规范。原因是在 ASP.NET Web API,一个 controller 是一个 class(类) 以处理 HTTP 请求(requests)。在 controller 里所有的公开方法(public methods)都称为 Action方法 或简称 Action。当 Web API Framework 接收到一个请求,它路由请求到一个 Action。

每个实体(entry)在路由表里都包含一个路由样板(route template)。Web API 的路由样板默认是 "api/{controller}/{id}",此样板里,"api" 是文字路径片段,{controller} 和 {id} 是定位参数。

当 Web API Framework 接收到一个 HTTP 请求,它会去尝试比对 URI 对路由表的路由样板列表, 如果没有符合的路由,Client 会收到一个 404 错误。例如,以下 URI 会符合默认路由:

· /api/Person

· /api/Person /1

路由表定义如:

config.Routes.MapHttpRoute( 

 name: "Default", 

 routeTemplate: "api/{controller}/{id}", 

 defaults: new { id = RouteParameter.Optional } 

 );

例如,一个 GET 请求,Web API 会查看那一个 action 是以 "Get..." 开头,比如 "GetContact" 或 "GetAllContacts"。同样规则适用在 GET, POST, PUT, DELETE 方法。你也能在 controller 里使用属性(attributes)去启用其他 HTTP 方法。

以下是一些可能 HTTP 请求及其含义:

HTTP Method

URI路径

Action

参数

GET

/api/Person

GetAllPeople

GET

/api/Person /1

GetPersonByID

1

DELETE

/api/Person /1

DeletePerson

1

POST

/api/Person

PostPerson

newPerson

当然,我们可以根据自己的实际需要修改这个路由表,如:

config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);

那么根据ID查询某个人就需要这样发送请求:

/api/person/ GetPersonByID/1

也可以访问到需要的资源。

3. 创建消费服务

根据项目的需要,你可以在你的API的客户端添加一个Person类。webapi懂得如何序列化和反序列化。NET类中的JSON或XML,都是使用中最常见的两种数据交换格式。

We can re-write our client examples to utilize a Person class if it suits our needs, and pass instances of Person to and from our API project indirectly through serialization. Our core client methods, re-written, look like this:

我们以控制台程序为例,新建一个控制台项目,假设命名为:RestApiClient

添加第一个类Person:

    public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

至于为什么要在这里还要添加一个Person类,我们可以想象WEB API机制,它是类似于Web Service的一种远程数据调用消息交换机制,服务器上使用的类本地是没有的,为了类型和序列化方便通常还要在消费端再次定义一次,加入您将消费放在服务端如以WCF的形式来进行,真正的客户端通过同步/异步请求来获取资源,那么另当别论。

然后新建一个类用来发送请求给WEB API,我们再次来分析这个类里面写些什么,列举一个方法:

        // 发送一个HTTP GET请求给Person Controller  API:
static JArray getAllPeople()
{
HttpClient client = new HttpClient();
HttpResponseMessage response =client.GetAsync("http://localhost:1296/api/person/").Result;
return response.Content.ReadAsAsync<JArray>().Result;
}

可以看出返回的是JArray格式。说明如下:

使用JSON前,需要引用Newtonsoft.Json的dll和using Newtonsoft.Json.Linq的命名空间。LINQ to JSON主要使用到JObject, JArray, JProperty和JValue这四个对象,JObject用来生成一个JSON对象,简单来说就是生成"{}",JArray用来生成一个JSON数组,也就是"[]",JProperty用来生成一个JSON数据,格式为key/value的值,而JValue则直接生成一个JSON值。下面我们就用LINQ to JSON返回上面分页格式的数据。

下面就是定义一个HttpClient去发送一个GET请求给指定WEB API,然后利用HttpResponseMessage接收返回的JSON数据。

完整代码如:

        // 发送一个HTTP GET请求给Person Controller  API:
static JArray getAllPeople()
{
HttpClient client = new HttpClient();
HttpResponseMessage response =client.GetAsync("http://localhost:1296/api/person/").Result;
return response.Content.ReadAsAsync<JArray>().Result;
} // 发送一个带ID参数的HTTP GET请求给Person Controller API
static JObject getPerson(int id)
{
HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAsync("http://localhost:1296/api/person/GetPersonByID/" + id).Result;
return response.Content.ReadAsAsync<JObject>().Result;
} // 发送一个匿名(类)对象HTTP POST给Person Controller API
static JObject AddPerson(string newLastName, string newFirstName)
{
// 初始化一个匿名对象
var newPerson = new { LastName = newLastName, FirstName = newFirstName };
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:1296/");
var response = client.PostAsJsonAsync("api/person", newPerson).Result;
return response.Content.ReadAsAsync<JObject>().Result; } static bool UpdatePerson(int personId, string newLastName, string newFirstName)
{
var newPerson = new { id = personId, LastName = newLastName, FirstName = newFirstName };
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:1296/");
var response = client.PutAsJsonAsync("api/person/", newPerson).Result;
return response.Content.ReadAsAsync<bool>().Result;
} static void DeletePerson(int id)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:1296/");
var relativeUri = "api/person/" + id.ToString();
var response = client.DeleteAsync(relativeUri).Result;
client.Dispose();
}

最不值钱的就是最终调用了,在Program类的Main方法中调用代码如下:

           Console.WriteLine("The Program will start......");

           JArray people = getAllPeople();
foreach (var person in people)
{
Console.WriteLine(person);
} Console.WriteLine(Environment.NewLine + "根据ID=2查询:");
JObject singlePerson = getPerson(2);
Console.WriteLine(singlePerson); Console.WriteLine(Environment.NewLine + "添加一个新对象并返回");
JObject newPerson = AddPerson("曼迪", "石");
Console.WriteLine(newPerson); Console.WriteLine(Environment.NewLine + "更新一个已经存在的对象并返回成功与否"); JObject personToUpdate = getPerson(2);
string newLastName = "麻子";
Console.WriteLine("Update Last Name of " + personToUpdate + "to " + newLastName); int id = personToUpdate.Value<int>("Id");
string FirstName = personToUpdate.Value<string>("FirstName");
string LastName = personToUpdate.Value<string>("LastName"); if (UpdatePerson(id, newLastName, FirstName))
{
Console.WriteLine(Environment.NewLine + "更新person:");
Console.WriteLine(getPerson(id));
} Console.WriteLine(Environment.NewLine + "删除ID为5的对象:"); DeletePerson(5); Console.WriteLine("输出所有对象");
people = getAllPeople();
foreach (var person in people)
{
Console.WriteLine(person);
}
Console.Read();

PS:

  1. 这里我偷了个懒,把他们写成一个部分类了,实际应该怎么写你懂得…
  2. 如果报每个方法最后一句出错,请加引用:"System.Net.Http.Formatting",可以在这里找到C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Net.Http.Formatting.dll真实的想法是实在不想加这个引用,原因请看下面。

另外遗憾的一点是我们对服务的消费操作并没有使用到纯异步操作也没有使用配置,只因我们讲述的是最简单的原理,后面会逐渐构建起一个完整的框架。敬请期待!

源码下载:请点击

使用ASP.NET web API创建REST服务(二)的更多相关文章

  1. 使用ASP.NET web API创建REST服务(三)

    本文档来源于:http://www.cnblogs.com/madyina/p/3390773.html Creating a REST service using ASP.NET Web API A ...

  2. MVC项目实践,在三层架构下实现SportsStore-09,ASP.NET MVC调用ASP.NET Web API的查询服务

    ASP.NET Web API和WCF都体现了REST软件架构风格.在REST中,把一切数据视为资源,所以也是一种面向资源的架构风格.所有的资源都可以通过URI来唯一标识,通过对资源的HTTP操作(G ...

  3. ASP.NET Web API 框架研究 服务容器 ServicesContainer

    ServicesContainer是一个服务的容器,可以理解为—个轻量级的IoC容器,其维护着一个服务接口类型与服务实例之间的映射关系,可以根据服务接口类型获取对应的服务实例.构成ASP.NET We ...

  4. 为 ASP.NET Web API 创建帮助页面(转载)

    转载地址:http://www.asp.net/web-api/overview/creating-web-apis/creating-api-help-pages 当创建web API 时,经常要创 ...

  5. Asp.Net Web API 2第十二课——Media Formatters媒体格式化器

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本教程演示如何在ASP.N ...

  6. 细说Asp.Net Web API消息处理管道(二)

    在细说Asp.Net Web API消息处理管道这篇文章中,通过翻看源码和实例验证的方式,我们知道了Asp.Net Web API消息处理管道的组成类型以及Asp.Net Web API是如何创建消息 ...

  7. ASP.NET Web API路由规则(二) 【转】

    http://www.cnblogs.com/liulun/archive/2012/06/20/2556556.html 默认的规则 在ASP.NET MVC4中 global.asax.cs代码中 ...

  8. ASP.NET Web API 创建帮助页

    1. 安装 Microsoft.AspNet.WebApi.HelpPage 程序包 Install-Package Microsoft.AspNet.WebApi.HelpPage 2. 注册 Ar ...

  9. asp.net web api集成微信服务(使用Senparc微信SDK)

    /// <summary> /// 微信请求转发控制器 /// </summary> [RoutePrefix("weixin")] public clas ...

随机推荐

  1. 模拟 Codeforces Round #203 (Div. 2) C. Bombs

    题目地址:http://codeforces.com/problemset/problem/350/C /* 题意:机器人上下左右走路,把其他的机器人都干掉要几步,好吧我其实没读懂题目, 看着样例猜出 ...

  2. 最短路(Dijkstra) POJ 1062 昂贵的聘礼

    题目传送门 /* 最短路:Dijkstra算法,首先依照等级差距枚举“删除”某些点,即used,然后分别从该点出发生成最短路 更新每个点的最短路的最小值 注意:国王的等级不一定是最高的:) */ #i ...

  3. BZOJ2783: [JLOI2012]树

    Description 数列 提交文件:sequence.pas/c/cpp 输入文件:sequence.in 输出文件:sequence.out 问题描述: 把一个正整数分成一列连续的正整数之和.这 ...

  4. 产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复

    产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复 用一个ArrayList存储1到100然后随机产生0到arraylist.size()之间的数字作为下标然后从arrayli ...

  5. 关于iOS测试机个数上限的详细规则

    关于iOS测试机个数上限的详细规则 前言 公司的iOS测试机快达到苹果规定的100个上限了,而因为the new iPad新出,我们需要新的quota来测试新iPad,所以就仔细研究了一下苹果关于10 ...

  6. Html - 圆圈border

    很多场景下需要对元素加入圆圈.但光靠border-radius其实还要调很久,所以做一下笔记 #binggan .mui-icon { display: inline-block; margin: 3 ...

  7. Scrum会议5(Beta版本)

    组名:天天向上 组长:王森 组员:张政.张金生.林莉.胡丽娜 代码地址:HTTPS:https://git.coding.net/jx8zjs/llk.git SSH:git@git.coding.n ...

  8. ionic 写一个五星评价(非指令)

    Controller里的代码: .controller('evaluateCtrl', function($scope, $state, $stateParams, $ionicPopup,$ioni ...

  9. discuz全局数组变量 后台各项设置 完整版

    $_G 保存了 Discuz! 中所有的预处理数据 缓存能够很好的提高程序的性能,一些配置数据没必要每次都查询数据库,只要在修改了的时候更新下缓存即可. Discuz! 中所有的缓存保存在 $_G[c ...

  10. Windows编译安装OpenSSL

    windows下使用vs2008中的nmake编译安装openssl的脚本build.bat: echo off & color 0A :: 项目名称 set PROJECT=openssl ...