ASP.NET Core 中文文档 第二章 指南(2)用 Visual Studio 和 ASP.NET Core MVC 创建首个 Web API
2016-06-10 08:41
1161 查看
原文:Building Your First Web API with ASP.NET Core MVC and Visual Studio
作者:Mike Wasson 和 Rick Anderson
翻译:谢炀(kiler)
校对:何镇汐、刘怡(AlexLEWIS)、后知后觉
HTTP 协议不仅仅提供网页服务。它也是一个构建公开服务和数据 API 的强大平台。HTTP 协议是简单、灵活、无处不在的。几乎你能想到的任何平台上都有 HTTP 支持,所以 HTTP 服务能够发送到多种客户端, 包括浏览器,移动设备和传统的桌面应用程序。
在本教程中,你将创建一个简单的 Web API 来管理一个 "to-do" 列表。在本教程中你无需编写任何 UI 代码。
ASP.NET Core 已经内置了用 MVC 架构 构建 Web API 的支持。统一了两个框架使得它易于构建应用程序,包括用户界面(HTML)和 API,因为现在它们共享相同的代码库和管道。
下面的图表展示了应用程序的基本设计:
不管是哪个调用 API 的客户端(浏览器、移动应用等)。我们不会在本教程编写客户端。
model 是一个代表你应用程序数据的类。在本案例中,只有一个模型 to-do 项。模型表现为简单 C# 类型 (POCOs),
controller 是一个处理 HTTP 请求并返回 HTTP 响应的对象。这个示例程序将只会有一个 controller。
为了保证教程简单我们不使用数据库。作为替代,我们会把 to-do 项存入内存。但是我们依然包含了一个数据访问层(不重要的),用来隔离 Web API和数据层。如果想使用数据库,参考用 Visual Studio 创建 ASP.NET Core MVC 应用程序。
选择 ASP.NET Core Web Application 项目模版。项目命名为
在 New ASP.NET Core Web Application (.NET Core) - TodoApi 对话框中,选择 Web API 模版。点击 OK。
添加一个名为 "Models" 的目录。在解决方案浏览器中, 右击项目。选择 Add > New Folder。把目录名命名为 Models。
注意
你可以把模型类放到项目的任何地方,但是 Models 是约定的默认目录。
下一步,添加一个
在 Add New Item 对话框中,选择 Class 模版。命名类为
将生成代码替换为:
定义一个名为
接口定义了基本的 CRUD 操作。
下一步,添加一个实现 ITodoRepository 接口的 TodoRepository 类:
生成应用程序确保没有任何编译错误。
这种方式可以更容易地对你的 Controller 进行单元测试。单元测试应该注入一个 Mock 或 stub 的 ITodoRepository。通过这样的方式测试范围可以限制在业务逻辑层而非数据访问层。
为了注入 repository 到 controller,我们必须注册DI容器。打开 Startup.cs 文件。添加以下指令:
在
将生成的代码替换为如下代码:
这里定义了一个空的 controller 类。下一个章节,我们将添加代码来实现 API。
以下是
在后面的教程中,我将会告诉你如何使用 Fiddler 工具查看 HTTP 响应。
在 controller 特性中标注模板:
替换模板中的
如果
对于
选择 Debug 选项卡,将 Launch URL 的值设置为
了解更多有关请求路由的信息请参考路由到控制器 Action。
相反,
如果没有数据项可以匹配 ID,方法会返回 404 错误,并最终以返回 NotFound 告终。
否则方法会返回 200 以及 JSON 响应正文。并最终以返回 ObjectResult 告终。
在 Visual Studio 中,点击
启动 Fiddler,从 File 菜单,取消选择 Capture Traffic 选项。这个会关闭捕获 HTTP traffic。
选择 Composer 页面。在 Parsed 选项卡中,输入
结果会显示在 sessions 列表中,响应码是200。使用 Inspectors 选项卡来查看响应内容,包括请求正文。
这是一个 HTTP POST 方法,用 [HttpPost] 特性声明。[FromBody] 特性告诉 MVC 从 HTTP 请求的正文中获取 to-do 项的值。
当通过客户端向服务器发出 POST 请求来创建新资源时,CreatedAtRoute 方法将返回标准的 201 响应。
我们使用 Fiddler 来创建和发送一个请求:
在 Composer 页面,从下拉框选择 POST。
在请求头的文本框中, 添加
在请求正文的文本框,输入以下内容:
点击 Execute。
这是一个简单的 HTTP 会话. 使用 Raw 选项卡查看会话数据.
Request:
Response:
方法返回 204 (无内容) 响应。这意味着客户端会收到 204 响应即使该项目已被删除,或者根本不存在。有两种方法来处理请求删除不存在资源的问题:
"Delete" 代表「删除一个已存在的项」,如果不存在返回 404。
"Delete" 代表「确保该项不在集合中」,如果项目不在集合中返回 204。
无论哪种方法是合理的。如果收到 404 错误,客户端将需要处理这种情况。
更多关于 API 部署的问题, 请参考发布与部署。
查看或者下载示例代码
返回目录
作者:Mike Wasson 和 Rick Anderson
翻译:谢炀(kiler)
校对:何镇汐、刘怡(AlexLEWIS)、后知后觉
HTTP 协议不仅仅提供网页服务。它也是一个构建公开服务和数据 API 的强大平台。HTTP 协议是简单、灵活、无处不在的。几乎你能想到的任何平台上都有 HTTP 支持,所以 HTTP 服务能够发送到多种客户端, 包括浏览器,移动设备和传统的桌面应用程序。
在本教程中,你将创建一个简单的 Web API 来管理一个 "to-do" 列表。在本教程中你无需编写任何 UI 代码。
ASP.NET Core 已经内置了用 MVC 架构 构建 Web API 的支持。统一了两个框架使得它易于构建应用程序,包括用户界面(HTML)和 API,因为现在它们共享相同的代码库和管道。
总览
这是你需要创建的 API :API | 描述 | 请求正文 | 响应正文 |
---|---|---|---|
GET /api/todo | 获取所有的to-do items | 无 | Array of to-do items |
GET /api/todo/{id} | 通过ID获取item | 无 | To-do item |
POST /api/todo | 添加一个新的item | To-do item | To-do item |
PUT /api/todo/{id} | 更新已经存在的item | To-do item | 无 |
DELETE /api/todo/{id} | 删除指定的item | 无 | 无 |
不管是哪个调用 API 的客户端(浏览器、移动应用等)。我们不会在本教程编写客户端。
model 是一个代表你应用程序数据的类。在本案例中,只有一个模型 to-do 项。模型表现为简单 C# 类型 (POCOs),
controller 是一个处理 HTTP 请求并返回 HTTP 响应的对象。这个示例程序将只会有一个 controller。
为了保证教程简单我们不使用数据库。作为替代,我们会把 to-do 项存入内存。但是我们依然包含了一个数据访问层(不重要的),用来隔离 Web API和数据层。如果想使用数据库,参考用 Visual Studio 创建 ASP.NET Core MVC 应用程序。
安装 Fiddler
我们不创建客户端,我们使用 Fiddler 来测试 API。Fiddler 是一个 Web 调试工具可以让您撰写的 HTTP 请求进行发送并查看原始的 HTTP 响应。创建项目
启动 Visual Studio。从 File 菜单, 选择 New > Project。选择 ASP.NET Core Web Application 项目模版。项目命名为
TodoApi并且点击 OK。
在 New ASP.NET Core Web Application (.NET Core) - TodoApi 对话框中,选择 Web API 模版。点击 OK。
添加模型类
模型表示应用程序中的数据对象。在本示例中,唯一使用到的模型是一个 to-do 项。添加一个名为 "Models" 的目录。在解决方案浏览器中, 右击项目。选择 Add > New Folder。把目录名命名为 Models。
注意
你可以把模型类放到项目的任何地方,但是 Models 是约定的默认目录。
下一步,添加一个
TodoItem类。右击 Models 目录并选择 Add > New Item。
在 Add New Item 对话框中,选择 Class 模版。命名类为
TodoItem并点击 OK。
将生成代码替换为:
namespace TodoApi.Models { public class TodoItem { public string Key { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } } }
添加仓储类
repository 类是一个封装了数据层的类,包含了获取数据并映射到实体模型类的业务逻辑。 尽管本例中不使用数据库,但依旧值得去思考 Repository 是如何注入到我们的 Controller 的。在 Models 目录下创建 repository 代码。定义一个名为
ITodoRepository的 repository 接口. 通过类模版 (Add New Item > Class)。
using System.Collections.Generic; namespace TodoApi.Models { public interface ITodoRepository { void Add(TodoItem item); IEnumerable<TodoItem> GetAll(); TodoItem Find(string key); TodoItem Remove(string key); void Update(TodoItem item); } }
接口定义了基本的 CRUD 操作。
下一步,添加一个实现 ITodoRepository 接口的 TodoRepository 类:
using System; using System.Collections.Generic; using System.Collections.Concurrent; namespace TodoApi.Models { public class TodoRepository : ITodoRepository { static ConcurrentDictionary<string, TodoItem> _todos = new ConcurrentDictionary<string, TodoItem>(); public TodoRepository() { Add(new TodoItem { Name = "Item1" }); } public IEnumerable<TodoItem> GetAll() { return _todos.Values; } public void Add(TodoItem item) { item.Key = Guid.NewGuid().ToString(); _todos[item.Key] = item; } public TodoItem Find(string key) { TodoItem item; _todos.TryGetValue(key, out item); return item; } public TodoItem Remove(string key) { TodoItem item; _todos.TryGetValue(key, out item); _todos.TryRemove(key, out item); return item; } public void Update(TodoItem item) { _todos[item.Key] = item; } } }
生成应用程序确保没有任何编译错误。
注册仓储
定义 repository 接口, 我们可以从使用它的 MVC Controller 解耦仓储类,而不是直接在 Controller 里面实例化TodoRepository,我们将会用 ASP.NET Core 内置功能注入
ITodoRepository,更多请参考依赖注入。
这种方式可以更容易地对你的 Controller 进行单元测试。单元测试应该注入一个 Mock 或 stub 的 ITodoRepository。通过这样的方式测试范围可以限制在业务逻辑层而非数据访问层。
为了注入 repository 到 controller,我们必须注册DI容器。打开 Startup.cs 文件。添加以下指令:
using TodoApi.Models;
在
ConfigureServices方法中,添加高亮方法:
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); // Add our repository type,下行高亮 services.AddSingleton<ITodoRepository, TodoRepository>(); }
添加控制器
在解决方案浏览器中,右击 Controllers 目录。选择 Add > New Item。在 Add New Item 对话框中,选择 Web API Controller Class 模版。命名为TodoController。
将生成的代码替换为如下代码:
using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using TodoApi.Models; namespace TodoApi.Controllers { [Route("api/[controller]")] public class TodoController : Controller { public TodoController(ITodoRepository todoItems) { TodoItems = todoItems; } public ITodoRepository TodoItems { get; set; } } }
这里定义了一个空的 controller 类。下一个章节,我们将添加代码来实现 API。
获取 to-do 列表
为了获取 to-do 项,添加下列方法到TodoController类。
public IEnumerable<TodoItem> GetAll() { return TodoItems.GetAll(); } [HttpGet("{id}", Name = "GetTodo")] public IActionResult GetById(string id) { var item = TodoItems.Find(id); if (item == null) { return NotFound(); } return new ObjectResult(item); }
以下是
GetAll方法 HTTP 响应:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Server: Microsoft-IIS/10.0 Date: Thu, 18 Jun 2015 20:51:10 GMT Content-Length: 82 [{"Key":"4f67d7c5-a2a9-4aae-b030-16003dd829ae","Name":"Item1","IsComplete":false}]
在后面的教程中,我将会告诉你如何使用 Fiddler 工具查看 HTTP 响应。
路由和 URL 路径
[HttpGet] 特性标明这些方法支持 HTTP GET,对 controller 中的方法标注 url 路径,有以下步骤:在 controller 特性中标注模板:
[Route("api/[controller]")];
替换模板中的
[Controller]为实际 controller 名称(在这里和以前一样,约定优于配置,所有 controller 都必须以
Controller结尾,模板中则可以省略
Controller后缀,译者注)。比如本例中的
TodoController,把
{controller}换成
todo即可。在 ASP.NET MVC Core 是大小写不敏感的。
如果
[HttpGet]也有一个模板,可以把它附加到路径后面,本例中不使用模板字符串。
对于
GetById方法,在实际 HTTP 请求中
{id}是一个占位符,客户端运行时使用
todo的 ID 属性;当 MVC 调用
GetById时,会把
{id}占位符分配到 Url 方法的
id参数中。
更换 "api/todo" 的启动 Url
右击项目 > Properties选择 Debug 选项卡,将 Launch URL 的值设置为
api/todo:
了解更多有关请求路由的信息请参考路由到控制器 Action。
返回值
GetAll方法返回 CLR 对象。MVC 自动把对象序列化为 JSON 并把 JSON 对象写入响应消息正文。响应状态码为 200,假设没有未处理异常的情况下。(未处理异常一般会被转化为 5xx 错误。)
相反,
GetById将会返回
IActionResult类型,它代表了更加通用的结果对象。因为
GetById有两个不同的返回值:
如果没有数据项可以匹配 ID,方法会返回 404 错误,并最终以返回 NotFound 告终。
否则方法会返回 200 以及 JSON 响应正文。并最终以返回 ObjectResult 告终。
使用 Fiddler 调用 API
这一步是可选的,但是有助于我们查看 Web API 返回的原始 HTTP 响应。在 Visual Studio 中,点击
^F5启动项目。Visual Studio 启动浏览器并导航到
http://localhost:port/api/todo,port 是一个随机数。如果你使用 Chrome、Edge 或者 Firefox 浏览器,todo 数据将会被显示。如果你使用 IE,IE 将会弹出窗口提示要求打开或者保存 todo.json 文件。
启动 Fiddler,从 File 菜单,取消选择 Capture Traffic 选项。这个会关闭捕获 HTTP traffic。
选择 Composer 页面。在 Parsed 选项卡中,输入
http://localhost:port/api/todo,port 是实际的端口号。点击 Execute 发送请求。
结果会显示在 sessions 列表中,响应码是200。使用 Inspectors 选项卡来查看响应内容,包括请求正文。
实现其他的 CRUD 操作
最后一步是为 Controller 增加Create、
Update以及
Delete这三个方法。这些方法都是围绕着一个主题,所以我将只列出代码以及标注出主要的区别。
Create
[HttpPost] public IActionResult Create([FromBody] TodoItem item) { if (item == null) { return BadRequest(); } TodoItems.Add(item); return CreatedAtRoute("GetTodo", new { controller = "Todo", id = item.Key }, item); }
这是一个 HTTP POST 方法,用 [HttpPost] 特性声明。[FromBody] 特性告诉 MVC 从 HTTP 请求的正文中获取 to-do 项的值。
当通过客户端向服务器发出 POST 请求来创建新资源时,CreatedAtRoute 方法将返回标准的 201 响应。
CreateAtRoute还把 Location 头信息加入到了响应。Location 头信息指定新创建的 todo 项的 URI。查看 10.2.2 201 Created。
我们使用 Fiddler 来创建和发送一个请求:
在 Composer 页面,从下拉框选择 POST。
在请求头的文本框中, 添加
Content-Type: application/json,意思是
Content-Type类型的头信息值为
application/json。Fiddler 会自动添加 Content-Length 头信息。
在请求正文的文本框,输入以下内容:
{"Name":"<你的 to-do 项目>"}
点击 Execute。
这是一个简单的 HTTP 会话. 使用 Raw 选项卡查看会话数据.
Request:
POST http://localhost:29359/api/todo HTTP/1.1 User-Agent: Fiddler Host: localhost:29359 Content-Type: application/json Content-Length: 33 {"Name":"Alphabetize paperclips"}
Response:
HTTP/1.1 201 Created Content-Type: application/json; charset=utf-8 Location: http://localhost:29359/api/Todo/8fa2154d-f862-41f8-a5e5-a9a3faba0233 Server: Microsoft-IIS/10.0 Date: Thu, 18 Jun 2015 20:51:55 GMT Content-Length: 97 {"Key":"8fa2154d-f862-41f8-a5e5-a9a3faba0233","Name":"Alphabetize paperclips","IsComplete":false}
Update
[HttpPut("{id}")] public IActionResult Update(string id, [FromBody] TodoItem item) { if (item == null || item.Key != id) { return BadRequest(); } var todo = TodoItems.Find(id); if (todo == null) { return NotFound(); } TodoItems.Update(item); return new NoContentResult(); }
Update类似于
Create,但是使用 HTTP PUT。响应是 204 (No Content)。根据 HTTP 规范,PUT 请求要求客户端发送整个实体更新,而不仅仅是增量。为了支持局部更新,请使用 HTTP PATCH。
Delete
[HttpDelete("{id}")] public void Delete(string id) { TodoItems.Remove(id); }
方法返回 204 (无内容) 响应。这意味着客户端会收到 204 响应即使该项目已被删除,或者根本不存在。有两种方法来处理请求删除不存在资源的问题:
"Delete" 代表「删除一个已存在的项」,如果不存在返回 404。
"Delete" 代表「确保该项不在集合中」,如果项目不在集合中返回 204。
无论哪种方法是合理的。如果收到 404 错误,客户端将需要处理这种情况。
下一步
关于如何为原生移动 App 创建后端, 请参考为原生移动应用创建后台服务。更多关于 API 部署的问题, 请参考发布与部署。
查看或者下载示例代码
返回目录
相关文章推荐
- 用 Visual Studio Code 在 macOS 上创建首个 ASP.NET Core 应用程序
- ASP.NET MVC中的Global.asax文件
- ASP.NET MVC中的Razor语法
- Configuring Autofac to work with the ASP.NET Identity Framework in MVC 5
- 从零开始搭建Raspberry Pi机器视觉编程环境
- ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL
- 约束路由 用正则表达式约束路由 Constraining a Route Using a Regular Expression 精通ASP-NET-MVC-5-弗瑞曼
- 性能工具MiniProfiler在Asp.Net WebForm跟踪EntityFramework
- AspNet Identity and IoC Container Registration
- CocoaPods和版本控制小技巧
- asp.net简单网站的实现
- Web Server 在iis下部署asp网站在iis下
- C#(asp.net)多线程用法示例(可用于同时处理多个任务)
- asp.net实现DropDownList,TreeView,ListBox的无限极分类目录树
- asp.net DataTable相关操作集锦(筛选,取前N条数据,去重复行,获取指定列数据等)
- asp.net提取多层嵌套json数据的方法
- 使用Aspose组件将WORD、PDF、PPT转为图片
- Asp.net MVC 移除不用的视图引擎
- ASP.NET Core 中文文档 第二章 指南(1)用 Visual Studio Code 在 macOS 上创建首个 ASP.NET Core 应用程序
- ASP.NET Core 中文文档 第一章 入门