您的位置:首页 > 编程语言 > ASP

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

2015-07-13 07:50 791 查看
CreatingaRESTserviceusingASP.NETWebAPI

Aservicethatiscreatedbaseduponthearchitectureof
RESTiscalledasRESTservice.AlthoughRESTlooksmoreinclinedtowebandHTTPitsprinciplescanbeappliedtootherdistributedcommunicationsystemsalso.OneoftherealimplementationofRESTarchitectureistheWorldWideWeb(WWW).RESTbased
servicesareeasytocreateandcanbeconsumedfromawidevarietyofdevices.

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

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

TherearemanyAPIsavailableindifferentlanguagestocreateandconsumeRESTservices.The
ASP.NETMVCbeta4comeswithanewAPIcalled
ASP.NETWebAPItocreateandconsumeRESTservices.WhilecreatingRESTservicesitisimportanttofollowtherulesandstandardsoftheprotocol(HTTP).Withoutknowingtheprinciplesof
RESTitiseasytocreateaservicethatlooksRESTfulbuttheyareultimatelyanRPCstyleserviceoraSOAP-RESThybridservice.InthisarticlewearegoingtoseehowtocreateasimpleRESTserviceusingtheASP.NETWebAPI.

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

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

开发工具:VisualStudio2013

创建步骤:

1.模型化数据

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



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



+ViewCode?
1
2
3
4
5
6
7
8
9
10
11
public
class
Person


{


public
int
Id{
get
;
set
;}


public
string
FirstName{
get
;
set
;}


public
string
LastName{
get
;
set
;}


}


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

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



+ViewCode?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public
interface
IPersonRepository


{


IEnumerable<Person>GetAll();


PersonGet(
int
id);


PersonAdd(Personperson);


void
Remove(
int
id);


bool
Update(Personperson);


}


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



+ViewCode?
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
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
PersonGet(
int

id)

{

return
_people.Find(p=>p.Id==id);

}


public
PersonAdd(Personperson)

{

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(Personperson)

{

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.使用ApiControllers访问API服务

UnlikeanASP.NET/MVCProject,whichgenerallyusesControllersderivedfromSystem.Web.MVC.Controller,aWebApiprojectwillgenerallyutilizecontrollersderivedfromSystem.Web.Http.WebApiController.LikethestandardMVCController,TheWebApiController
acceptsincomingHTTPrequestsandprocessesaccordingly.However,thestandardMVCControllerreturnsaView,whiletheWebApicontrollerreturnsdata.

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

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



命名为PersonController。

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



+ViewCode?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static
readonly
IPersonRepositorydatabasePlaceholder=
new
PersonRepository();


public
PersonGetPersonByID(
int

id)


{


Personperson=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异常,表示请求资源不存在。实际项目中,我们是非常有必要返回一些和操作对应的异常信息的。

完整代码如:

+ViewCode?
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
public
class
PersonController:ApiController

{

static
readonly
IPersonRepositorydatabasePlaceholder=
new
PersonRepository();



public
PersonGetPersonByID(
int

id)

{

Personperson=databasePlaceholder.Get(id);

if
(person==
null
)

{

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

throw
new
HttpResponseException(HttpStatusCode.NotFound);

}

return
person;

}


public
IEnumerable<Person>GetAllPeople()

{

return
databasePlaceholder.GetAll();

}


public
HttpResponseMessagePostPerson(Personperson)

{

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(Personperson)

{

if
(!databasePlaceholder.Update(person))

{

throw
new
HttpResponseException(HttpStatusCode.NotFound);

}

return
true
;

}


public
void
DeletePerson(
int

id)

{

Personperson=databasePlaceholder.Get(id);

if
(person==
null
)

{

throw
new
HttpResponseException(HttpStatusCode.NotFound);

}

databasePlaceholder.Remove(id);

}

}


Aswehavealludedtopreviously,acoretenetofMVCistofavorConventionoverConfiguration.Intermsofourcontrollerclass,whatthismeansisthattheASP.NET/MVCruntimeestablishescertaindefaultbehaviorswhichrequirenoadditionalconfiguration,unlessyouwanttochangethem.Initially,formeanyway,thiswasalsoasourceofconfusion,astheruntimeappearedtoperformsufficient"magic"thatIdidn'tknowwhatwashappening.
当然其中一个非常重要的WebAPI规范就是HTTP谓词的映射,如GET、POST、PUT、DELETE。那么正如我们上面所述,我们的动作也遵循了这个规范。原因是在ASP.NETWebAPI,一个controller是一个class(类)以处理HTTP请求(requests)。在controller里所有的公开方法(publicmethods)都称为Action方法或简称Action。当WebAPIFramework接收到一个请求,它路由请求到一个Action。

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

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

·/api/Person

·/api/Person/1

路由表定义如:

?
1
2
3
4
5
6
7
8
9
config.Routes.MapHttpRoute(


name:
"Default"
,


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


defaults:
new
{id=RouteParameter.Optional}


);


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

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

HTTPMethod

URI路径

Action

参数

GET

/api/Person

GetAllPeople



GET

/api/Person/1

GetPersonByID

1

DELETE

/api/Person/1

DeletePerson

1

POST

/api/Person

PostPerson

newPerson

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

?
1
2
3
4
5
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,都是使用中最常见的两种数据交换格式。

Wecanre-writeourclientexamplestoutilizeaPersonclassifitsuitsourneeds,andpassinstancesofPersontoandfromourAPIprojectindirectlythroughserialization.Ourcoreclientmethods,re-written,looklikethis:

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

添加第一个类Person:

+ViewCode?
1
2
3
4
5
6
public
class
Person

{

public
int
Id{
get
;
set
;}

public
string
FirstName{

get
;
set
;}

public
string
LastName{

get
;
set
;}

}


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

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

+ViewCode?
1
2
3
4
5
6
7
//发送一个HTTPGET请求给PersonControllerAPI:

static
JArraygetAllPeople()

{

HttpClientclient=
new
HttpClient();

HttpResponseMessageresponse=client.GetAsync(
"http://localhost:1296/api/person/"
).Result;

return
response.Content.ReadAsAsync<JArray>().Result;

}


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

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

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

完整代码如:



+ViewCode?
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
//发送一个HTTPGET请求给PersonControllerAPI:

static
JArraygetAllPeople()

{

HttpClientclient=
new
HttpClient();

HttpResponseMessageresponse=client.GetAsync(
"http://localhost:1296/api/person/"
).Result;

return
response.Content.ReadAsAsync<JArray>().Result;

}


//发送一个带ID参数的HTTPGET请求给PersonControllerAPI

static
JObjectgetPerson(
int
id)

{

HttpClientclient=
new
HttpClient();

HttpResponseMessageresponse=client.GetAsync(
"http://localhost:1296/api/person/GetPersonByID/"

+id).Result;

return
response.Content.ReadAsAsync<JObject>().Result;

}


//发送一个匿名(类)对象HTTPPOST给PersonControllerAPI

static
JObjectAddPerson(
string

newLastName,
string
newFirstName)

{

//初始化一个匿名对象

var
newPerson=
new

{LastName=newLastName,FirstName=newFirstName};

HttpClientclient=
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};

HttpClientclient=
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)

{

HttpClientclient=
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方法中调用代码如下:



+ViewCode?
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
Console.WriteLine(
"TheProgramwillstart......"
);


JArraypeople=getAllPeople();

foreach
(
var
person
in

people)

{

Console.WriteLine(person);

}



Console.WriteLine(Environment.NewLine+
"根据ID=2查询:"
);

JObjectsinglePerson=getPerson(2);

Console.WriteLine(singlePerson);



Console.WriteLine(Environment.NewLine+
"添加一个新对象并返回"
);

JObjectnewPerson=AddPerson(
"曼迪"
,
"石"
);

Console.WriteLine(newPerson);



Console.WriteLine(Environment.NewLine+
"更新一个已经存在的对象并返回成功与否"
);


JObjectpersonToUpdate=getPerson(2);

string
newLastName=
"麻子"
;

Console.WriteLine(
"UpdateLastNameof"
+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:

这里我偷了个懒,把他们写成一个部分类了,实际应该怎么写你懂得…

如果报每个方法最后一句出错,请加引用:"System.Net.Http.Formatting",可以在这里找到C:\ProgramFiles(x86)\MicrosoftASP.NET\ASP.NETMVC4\Assemblies\System.Net.Http.Formatting.dll真实的想法是实在不想加这个引用,原因请看下面。

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

源码下载:请点击
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: