一.概述
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调用的配置和注意事项,请查看官网介绍。
备注: api站点添加静态资源访问,如访问localhost:8080/Resource/ikdict/extword.txt
app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider( Path.Combine(Directory.GetCurrentDirectory(), @"Resource/IKdict")),//这是本机路径 RequestPath = new PathString("/Resource/IKdict")//访问路径 });
参考文献: