WEBAPI系列(⼀):WEBAPI的适⽤场景、第⼀个实例在我前⼀篇博客中已经给各位简单介绍了HTTP协议与RestFul API的关系,以及⼀些基本的HTTP协议知识,在这些知识的铺垫下,今天,我们⼀起来讨论⼀下WEB API的适⽤场景,然后写我们第⼀个WEB API接⼝,并演⽰如何对其进⾏简单调⽤。
很多⼈都很迷惑,既然有了WCF为什么还要有WEB API?WEB API会不会取代WCF?
就我的看法,WCF提供的是⼀种RPC实现的集合,WCF的设计更多地考虑了SOA的场景,以及各种RPC的问题。很多⼈也会说,RestFul API也是⼀种RPC啊,并且WCF 中也有关于RestFul 的实现啊。很多资料中RPC和RestFul在风格概念上是有⼀些区别的,其实我觉得这两者的区别⽐较主观,过度纠结这些就学院派了;我主要关注了实际使⽤上的⼀些问题,在WCF中,⽀持的协议很多,WS-*系列协议,以及⼀些更简洁的协议,其中提供了⼀些专⽤通信协议的性能是⾮常⾼的,并且WCF还提供了服务发现等功能,我认为WCF更适合内部系统间的⾼性能调⽤,社区中也有其他⼀些RPC⽅案可以选择,例如gRPC,Avor,thrift都是和WCF定位相同的产品;⽽WEB API是关注于HTTP RestFul风格的产品,在此基础上,任何语⾔、任何终端都能⾮常容易地进⾏对接,并且能利⽤⾮常成熟的各种HTTP基础设施和解决⽅案来进⾏开发、调试、负载均衡、内容分发。所以,WEB API是⼀种针对HTTP的,偏重于快速开发RestFul风格开放式API的开发框架。⽬前看来,他并不能取代WCF,他们各有适合的场景,不能认为WEB API是WCF的替代产品。
OK,现在我们来开发第⼀组WEB API接⼝!使⽤VS2012以后的版本都有现成的WEB API创建模板,⼤家跟着创建就好了,创建出来后,项⽬中会有MVC、WEB API的项⽬,WEB API对MVC有依赖,不能单独创建!⽽WEB API和MVC都是利⽤类似的路由机制,所以在默认路由中,WEB API 使⽤
/api/{controller}/{id}
作为路由,添加了/api/节以区分MVC和web api。
接下来,我们添加⼀个WEB API的Controller,取名为PersonController,他继承于ApiController;在创建这个Controller的时候,我们就定义了⼀种资源:Person,在PersonController⾥的所有操作均围绕着Person这个资源来的。接下来我们开始定义⼀组增删改查操作。
在Web API中,默认路由采⽤了⼀种约定:根据谓词来进⾏路由,⽽⽅法名的前缀就是调⽤该⽅法对应使⽤的HTTP谓词。代码⽰例如下:
///<summary>
/// Person 为资源,对Person进⾏的⼀组操作
///</summary>
public class PersonController : ApiController
{
private static List<Person> _personLst = new List<Person>();
///<summary>
///获取⼀个Person
///</summary>
///<param name="id">Person的ID</param>
///<returns>Person</returns>
public Person GetPerson(long id)
{
return _personLst.Find(x => x.Id == id);
}
///<summary>
///添加⼀个Person
///</summary>
///<param name="person">Person</param>
public void PostAddPerson(Person person)
{
_personLst.Add(person);
}
///<summary>
///修改⼀个
/
//</summary>
///<param name="id">Person Id</param>
///<param name="person">新</param>
public void PutModifyPerson(long id, Person person)
{
var p = _personLst.Find(x => x.Id == id);
p.Age = person.Age;
p.Name = person.Name;
p.Sex = person.Sex;
}
///<summary>
/
//删除⼀个Person
///</summary>
///<param name="id">Person ID</param>
public void DeletePerson(long id)
{
_personLst.RemoveAll(x => x.Id == id);
}
}
⼀个简单的针对资源的CRUD操作的API就好了,不⽤解析输⼊,不⽤拼接输出,就是那么简单!让我们来遛⼀遛!
浏览器json格式化发送请求:谓词为POST,语义创建Person,Person描述在Body⾥,head中声明了Body通过Json序列化。
收到响应:响应码204,属于2XX类型执⾏成功,Body⾥没有数据
发送请求:谓词为GET,语义为查询Person资源,Id为1的,head中声明希望接收使⽤XML序列化的数据
收到响应:响应码为200,执⾏成功,Body中有数据,数据使⽤XML序列化
发送请求:谓词为PUT,语义为修改ID为1的Person资源,修改内容在Body中,Content-Type标明Body使⽤Json序列化,在Body中我们将Name修改为Test1Changed 收到响应,响应码为204,执⾏成功
发送请求:谓词为GET,语义为查询ID为1的Person资源,Accept标明希望接收到Json数据
收到响应:可以看到Body为使⽤Json序列化的内容,Name属性已经变更为Test1Changed
发送请求:谓词为DELETE,语义为删除ID为1的Person资源
收到响应:响应码204,执⾏成功
发送请求:谓词为GET,语义为查询ID为1的Person资源,Accept标明希望接收到Json数据
收到响应:响应码为200,执⾏成功,响应内容为null,资源已删除
这就是我⽤Fiddler来发送、调⽤的⼀组RestFul接⼝,⼤家可以看到,整个调⽤过程使⽤到了HTTP的语义,⽤到了谓词路由、内容协商。在增、删、改操作中,我都是使⽤void 作为返回值,根据HTTP Code 判断,⼤家也可以⾃定义⼀些返回数据来做出更进⼀步的操作描述。
在写了这些API后,我们需要在程序中调⽤,我以C#为例写⼀组对这些接⼝调⽤的实现。在C#中,传统调⽤HTTP接⼝⼀般有两种办法: WebRequest/WebResponse组合的⽅法调⽤和WebClient类进⾏调⽤。第⼀种⽅法抽象程度较低,使⽤较为繁琐;⽽WebClient主要⾯向了WEB⽹页场景,在模拟Web操作时使⽤较为⽅便,但⽤在RestFul场景下却⽐较⿇烦,在Web API发布的同时,.NET提供了两个程序集:System.Net.Http和System.Net.Http.Formatting。这两个程序集中最核⼼的类是HttpClient。在.NET4.5中带有这两个程序集,⽽.NET4需要到Nuget⾥下载Microsoft.Net.Http和Microsoft.AspNet.WebApi.Client这两个包才能使⽤这个类,更低的.NET版本就只能表⽰遗憾了只能⽤WebRequest/WebResponse或者WebClient来调⽤这些API了。
在使⽤中,System.Net.Http这个程序集提供了HttpClient类以及相关的HTTP调⽤,⽽System.Net.Http.Formatting提供了⼀些针对HttpClient的帮助扩展,更好地⽀持了内容协商、Content创建等功能。下⾯我就和⼤家⼀起写⼀下这个例⼦:
我们新建⼀个控制台程序:
代码如下:
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Sex { get; set; }
public override string ToString()
{
return $"Id={Id} Name={Name} Age={Age} Sex={Sex}";
}
}
class Program
{
static void Main(string[] args)
{
var client = new HttpClient();
client.BaseAddress = new Uri("localhost:22658/"); //基本的API URL
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //默认希望响应使⽤Json序列化
Run(client);
Console.ReadLine();
}
static async void Run(HttpClient client)
{
var result = await AddPerson(client);
Console.WriteLine($"添加结果:{result}"); //添加结果:true
var person = await GetPerson(client);
Console.WriteLine($"查询结果:{person}"); //查询结果:Id=1 Name=test Age=10 Sex=F
result = await PutPerson(client);
Console.WriteLine($"更新结果:{result}"); //更新结果:true
result = await DeletePerson(client);
Console.WriteLine($"删除结果:{result}"); //删除结果:true
}
static async Task<bool> AddPerson(HttpClient client)
{
return await client.PostAsJsonAsync("api/Person", new Person() { Age = 10, Id = 1, Name = "test", Sex = "F" }) //向Person发送POST请求,Body使⽤Json进⾏序列化
.ContinueWith(x => x.Result.IsSuccessStatusCode);  //返回请求是否执⾏成功,即HTTP Code是否为2XX
}
static async Task<Person> GetPerson(HttpClient client)
{
return await await client.GetAsync("api/Person/1") //向Person发送GET请求
.ContinueWith(x => x.Result.Content.ReadAsAsync<Person>(                              //获取返回Body,并根据返回的Content-Type⾃动匹配格式化器反序列化Body new List<MediaTypeFormatter>() {new JsonMediaTypeFormatter()/*这是Json的格式化器*/
,new XmlMediaTypeFormatter()/*这是XML的格式化器*/}));
}
static async Task<bool> PutPerson(HttpClient client)
{
return await client.PutAsJsonAsync("api/Person/1", new Person() { Age = 10, Id = 1, Name = "test1Change", Sex = "F" }) //向Person发送PUT请求,Body使⽤Json进⾏序列化
.ContinueWith(x => x.Result.IsSuccessStatusCode);  //返回请求是否执⾏成功,即HTTP Code是否为2XX
}
static async Task<bool> DeletePerson(HttpClient client)
{
return await client.DeleteAsync("api/Person/1") //向Person发送DELETE请求
.ContinueWith(x => x.Result.IsSuccessStatusCode); //返回请求是否执⾏成功,即HTTP Code是否为2XX
}
}
这就完成了这组API的调⽤,是不是⾮常简单⽅便?HTTPClient使⽤全异步的⽅法,并且他有良好的扩展性,我会在之后的博客中再聊这个问题。
OK,到此为⽌⼀组简单的Restful API和C#的调⽤客户端就完成了,但这只是开始,Web API是⼀个很强⼤的框架,他的扩展点⾮常丰富,这些扩展能为我们的开发提供很多的帮助,下⼀篇博⽂我将为⼤家带来WEB API中Filter的使⽤。
博⽂中如有不正确的地⽅欢迎⼤家指正。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。