asp.net core系列 36 WebAPI 搭建详细示例
一.概述
http不仅仅用于提供网页。http也是构建公开服务和数据的api强大平台。http简单灵活且无处不在。几乎任何你能想到的平台都有一个http库,因此http服务可以覆盖广泛的客户端,包括浏览器,移动设备和传统的桌面应用程序。
asp.net web api 是一个框架,基于.net framework 或.net core 之上构建 web api。
从本章开始学习web api系列时,先从一个示例开始,下面使用asp.net core mvc 创建 web api。通过本次演示将了解到一个基础的web api应用。环境使用vs 2017 +sql server 2012。示例主要知识点包括:
(1)创建 web api 项目。
(2)添加模型类。
(3)创建数据库上下文。
(4)注册数据库上下文。
(5)添加控制器。
(6)添加 crud 方法。
(7)配置路由和 url 路径。
(8)指定返回值。
(9)使用fiddle调用 web api。
(10)使用 jquery 调用 web api。
在开发web api之前,先制定几个有针对性的api 接口,至于api 接口业务很简单,主要是演示如何应用web api。
api接口 |
说明 |
请求报文 |
响应报文 |
get /api/todo |
获取所有待办事项 |
无 |
待办事项的数据 |
get /api/todo/{id} |
按 id 获取项 |
无 |
待办事项 |
post /api/todo |
添加新项 |
待办事项 |
待办事项 |
put /api/todo/{id} |
更新现有项 |
待办事项 |
无 |
delete /api/todo/{id} |
删除项 |
无 |
无 |
1.1 创建web项目
(1)从“文件”菜单中选择“新建” > “项目”。
(2)选择“asp.net core web 应用程序”模板。 将项目命名为 todoapi,然后单击“确定”。
(3)在“新建 asp.net core web 应用程序 - todoapi”对话框中,选择 asp.net core 版本。 选择“api”模板,然后单击“确定”。 请不要选择“启用 docker 支持”。
项目模板会创建 values
api。 控制器方法中默认的http[verb] 属性路由包括get,post, put, delete接口
1.2 添加模型类
在项目中,添加models文件夹,新建一个 todoitem
类,如下所示:
public class todoitem { //主键 public long id { get; set; } //待办事项名称 public string name { get; set; } //是否完成 public bool iscomplete { get; set; } }
1.3 添加数据库上下文
在“models”文件夹,然后选择“添加” > “类”。 将类命名为 todocontext,如下所示:
//using microsoft.entityframeworkcore; public class todocontext: dbcontext { public todocontext(dbcontextoptions<todocontext> options) : base(options) { } public dbset<todoitem> todoitems { get; set; } }
1.4 注册上下文
在 asp.net core 中,服务(如数据库上下文)必须向依赖关系注入 (di) 容器进行注册。 该容器向控制器提供服务。这里使用microsoft.entityframeworkcore.sqlserver数据提供程序。再根据模型生成数据库表(库名todo,有一个表todoitem)。关于如何安装数据提供程序,以及如何用模型生成数据库表,请参考“asp.net core 系列第 20 篇” 。使用迁移生成数据库后,如下所示:
1.5 添加控制器
在controllers 文件夹中,选择“api 控制器类”模板。将类命名为 todocontroller.cs, 代码如下所示:
[route("api/[controller]")] [apicontroller]//添加特性,代表是一个web api控制器类 public class todocontroller : controller { private readonly todocontext _context; /// <summary> /// 实例化一个ef上下文,进行数据库操作。开始初始入库一条数据 /// </summary> /// <param name="context"></param> public todocontroller(todocontext context) { _context = context; if (_context.todoitems.count() == 0) { // create a new todoitem if collection is empty, // which means you can't delete all todoitems. _context.todoitems.add(new todoitem { name = "item1" }); _context.savechanges(); } } }
1.6 添加get方法
通过get方法来查询待办事项的 api,将以下方法添加到 todocontroller 类中。关于路由知识,请参考asp.net core 系列第5篇。
/// <summary> /// 获取所有事项 /// get: api/todo /// </summary> /// <returns></returns> [httpget] public async task<actionresult<ienumerable<todoitem>>> gettodoitems() { //using microsoft.entityframeworkcore; return await _context.todoitems.tolistasync(); } /// <summary> /// 根据id,获取一条事项 /// get: api/todo/5。 id 是参数,代表路由合并 /// </summary> /// <param name="id"></param> /// <returns></returns> [httpget("{id}")] public async task<actionresult<todoitem>> gettodoitem(long id) { var todoitem = await _context.todoitems.findasync(id); if (todoitem == null) { return notfound(); } return todoitem; }
启动vs,测试结果,如下所示,注意请求wep api 地址与action的方法名没有关系,是根据方法名之上的http[verb]特性来确定url地址的:
1.7 路由和url路径
(1) route特性
route是用来制定路由模板的,在第5章中也讲到。[route("api/[controller]")]中是以api开头,替换[controller]
为控制器的名称, 按照惯例,控制器类名称减去“controller”后缀, 因此控制器名称为“todo” ,路由不区分大小写。
(2) httpget
如果[httpget]
属性具有路径模板,例如:[httpget("{id}")]
,
则将其
附加到路径
(如:api/todo/1)
。在这个示例中
,
"{id}"
是占位符变量,用于待办事项的唯一标识符。
1.8 返回值
上面的gettodoitems和gettodoitem方法的返回类型是actionresult <t>类型。asp.net core自动将对象序列化为json,并将json写入响应消息的正文中。假设没有异常,此返回类型的响应代码为200。未处理的异常被转换为5xx错误。
actionresult
返回类型可以表示各种http状态代码,例如在上面的gettodoitem
方法中
可以返回两个不同的状态值:一个是成功的200, 一个是404未到找。所有的http状态代码可以在controllerbase中找到,例如下图中的forbid() 是http状态码403,nocontent()是http 状态码204 。 等等
二.测试web api
下面简单使用fiddler来测试一下增删改增。先在本机vs 2017中启动该项目,地址为http://localhost:62271。
2.1 查询
在fiddler工具中,选择get,输入查询的http地址,右边是响应的http 状态码200, 以及查询的json结构对象。
2.2 新增
下面创建方法,添加以下 posttodoitem 方法,在新增方法中调用了createdataction内置方法,如果新增成功,则返回 http 201 状态代码。http 201是http post方法的标准响应,该方法在服务器上创建新资源。
//post: api/todo [httppost] public async task<actionresult<todoitem>> posttodoitem(todoitem item) { _context.todoitems.add(item); await _context.savechangesasync(); return createdataction(nameof(gettodoitem), new { id = item.id }, item); }
2.3 修改
添加以下 puttodoitem
方法, puttodoitem 与 posttodoitem 类似,但是使用的是 http put。 响应是 204(无内容)。 根据 http 规范,put 请求需要客户端发送整个更新的实体,而不仅仅是更改。若要支持部分更新,请使用httppatch特性。
// put: api/todo/1 [httpput("{id}")] public async task<iactionresult> puttodoitem(long id, todoitem item) { if (id != item.id) { //http 403 return badrequest(); } //当前传过来的实体添加到上下文,并设置为修改 _context.entry(item).state = entitystate.modified; await _context.savechangesasync(); return nocontent(); }
2.4 删除
// delete: api/todo/2 [httpdelete("{id}")] public async task<iactionresult> deletetodoitem(long id) { var todoitem = await _context.todoitems.findasync(id); if (todoitem == null) { return notfound(); } _context.todoitems.remove(todoitem); await _context.savechangesasync(); return nocontent(); }
最后:关于jquery 调用 web api,不再演示,jquery调用的配置和注意事项,请查看官网介绍。
参考文献: