在本文中,我们将一起查看TodoController 类代码。

[Route] 属性定义了Controller的URL 模板:

  1. [Route("api/[controller]")]

所有符合该模板类型的HTTP 请求都会被路由到该controller。在本例中, 路由的命名规范为对应Controller 的前缀,对于TodoController 类,路由模板为 “api/todo”。

HTTP 方法

[HttpGet][HttpPost][HttpDelete] 属性定义为 controller 动作对应的HTTP 方法 (另外也有[HttpPut][HttpPatch] 属性,在本示例中没有使用。)

  1. [HttpGet]
  1. public IEnumerable<TodoItem> GetAll() {}
  1.  
  1. [HttpGet("{id:int}", Name = "GetByIdRoute")]
  1. public IActionResult GetById (int id) {}
  1.  
  1. [HttpPost]
  1. public void CreateTodoItem([FromBody] TodoItem item) {}
  1.  
  1. [HttpDelete("{id:int}")]
  1. public IActionResult DeleteItem(int id) {}

GetById 和DeleteItem 方法中的参数可以增加路由的传递信息。所以,路由模板更加完善的写法为“api/[controller]/{id:int}”。

在 “{id:int}” 中,id是变量,而 “:int” 代表参数为整型。以下为URLs实例:

  1. http://localhost/api/todo/1
  1. http://localhost/api/todo/42

不能写为:

  1. http://localhost/api/todo/abc

注意 GetById 和 DeleteItem 方法同样拥有命名为id的参数。framework 会自动传递实参值到Controller中。例如,如果URL为http://localhost/api/todo/42,id的值则为42,这个过程为参数绑定。

CreateTodoItem 方法代表了另一个参数绑定:

  1. [HttpPost]
  1. public void CreateTodoItem([FromBody] TodoItem item) {}

[FromBody] 属性指定framework 从Request中反序列化TodoItem 参数。

以下是request和controller 动作的对应列表:

Request

Controller Action

GET /api/todo

GetAll

POST /api/todo

CreateTodoItem

GET /api/todo/1

GetById

DELETE /api/todo/1

DeleteItem

GET /api/todo/abc

none – returns 404

PUT /api/todo

none – returns 404

最后两个例子由于其他用途返回404 错误。例如 'GET /api/todo/abc', 'abc' 实参是GetById 方法中要求的整型数据类型。

Action 返回值

TodoController 类展示了多种 controller action的返回值方法。

GetAll 方法返回了一个CLR 对象。

  1. [HttpGet]
  1. public IEnumerable<TodoItem> GetAll()
  1. {
  1. return _items;
  1. }

返回对象的序列化信息被存储到Response消息中。默认格式为JSON,客户端同样可以接收XML数据格式:

  1. GET http://localhost:5000/api/todo HTTP/1.1
  1.  
  1. User-Agent: Fiddler
  1.  
  1. Host: localhost:5000
  1.  
  1. Accept: application/xml

Response:

  1. HTTP/1.1 200 OK
  1. Content-Type: application/xml;charset=utf-8
  1. Server: Microsoft-HTTPAPI/2.0
  1. Date: Thu, 30 Oct 2014 22:40:10 GMT
  1. Content-Length: 228
  1.  
  1. <ArrayOfTodoItem xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/TodoApi.Models"><TodoItem><Id>1</Id><IsDone>false</IsDone><Title>First Item</Title></TodoItem></ArrayOfTodoItem>

GetById 方法返回了一个IActionResult 接口:

  1. [HttpGet("{id:int}", Name = "GetByIdRoute")]
  1. public IActionResult GetById (int id)
  1. {
  1. var item = _items.FirstOrDefault(x => x.Id == id);
  1. if (item == null)
  1. {
  1. return HttpNotFound();
  1. }
  1.  
  1. return new ObjectResult(item);
  1. }

如果有URL中对应的id,则这个方法会返回ObjectResult 。返回 ObjectResult 和返回CLR 模型相同。而方法中规定返回类型为IActionResult。因此,该方法可以返回不同的类型。

如果没有对应ID,则返回HttpNotFound,页面会抛出404 错误。

最后, CreateTodoItem 方法展示如何直接在方法中设置返回值:

  1. [HttpPost]
  1. public void CreateTodoItem([FromBody] TodoItem item)
  1. {
  1. // (some code not shown here)
  1.  
  1. Context.Response.StatusCode = 201;
  1. Context.Response.Headers["Location"] = url;
  1. }

这种方法的缺陷是很难进行单元测试。(关于测试相关讨论,可以参考Unit Testing Controllers in ASP.NET Web API)。

依赖注入

MVC 6 内置了依赖注入功能。下面,让我们创建一个包含ToDo列表的repository 类。

首先,为repository定义一个接口:

  1. using System.Collections.Generic;
  1.  
  1. namespace TodoApi.Models
  1. {
  1. public interface ITodoRepository
  1. {
  1. IEnumerable<TodoItem> AllItems { get; }
  1. void Add(TodoItem item);
  1. TodoItem GetById(int id);
  1. bool TryDelete(int id);
  1. }
  1. }

之后定义具体实现方法。

  1. using System;
  1. using System.Collections.Generic;
  1. using System.Linq;
  1.  
  1. namespace TodoApi.Models
  1. {
  1. public class TodoRepository : ITodoRepository
  1. {
  1. readonly List<TodoItem> _items = new List<TodoItem>();
  1.  
  1. public IEnumerable<TodoItem> AllItems
  1. {
  1. get
  1. {
  1. return _items;
  1. }
  1. }
  1.  
  1. public TodoItem GetById(int id)
  1. {
  1. return _items.FirstOrDefault(x => x.Id == id);
  1. }
  1.  
  1. public void Add(TodoItem item)
  1. {
  1. item.Id = 1 + _items.Max(x => (int?)x.Id) ?? 0;
  1. _items.Add(item);
  1. }
  1.  
  1. public bool TryDelete(int id)
  1. {
  1. var item = GetById(id);
  1. if (item == null)
  1. {
  1. return false;
  1. }
  1. _items.Remove(item);
  1. return true;
  1. }
  1. }
  1. }

使用构造函数注入repository 到 controller:

  1. [Route("api/[controller]")]
  1. public class TodoController : Controller
  1. {
  1. // Remove this code:
  1. //static readonly List<TodoItem> _items = new List<TodoItem>()
  1. //{
  1. // new TodoItem { Id = 1, Title = "First Item" }
  1. //};
  1.  
  1. // Add this code:
  1. private readonly ITodoRepository _repository;
  1.  
  1. public TodoController(ITodoRepository repository)
  1. {
  1. _repository = repository;
  1. }

然后更新controller 方法到repository:

  1. [HttpGet]
  1. public IEnumerable<TodoItem> GetAll()
  1. {
  1. return _repository.AllItems;
  1. }
  1. [HttpGet("{id:int}", Name = "GetByIdRoute")]
  1. public IActionResult GetById(int id)
  1. {
  1. var item = _repository.GetById(id);
  1. if (item == null)
  1. {
  1. return HttpNotFound();
  1. }
  1.  
  1. return new ObjectResult(item);
  1. }
  1.  
  1. [HttpPost]
  1. public void CreateTodoItem([FromBody] TodoItem item)
  1. {
  1. if (!ModelState.IsValid)
  1. {
  1. Context.Response.StatusCode = 400;
  1. }
  1. else
  1. {
  1. _repository.Add(item);
  1.  
  1. string url = Url.RouteUrl("GetByIdRoute", new { id = item.Id }, Request.Scheme, Request.Host.ToUriComponent());
  1. Context.Response.StatusCode = 201;
  1. Context.Response.Headers["Location"] = url;
  1. }
  1. }
  1.  
  1. [HttpDelete("{id}")]
  1. public IActionResult DeleteItem(int id)
  1. {
  1. if (_repository.TryDelete(id))
  1. {
  1. return new HttpStatusCodeResult(204); // 201 No Content
  1. }
  1. else
  1. {
  1. return HttpNotFound();
  1. }
  1. }

我们需要注册repository到依赖注入系统才能使其启作用。在Startup 类中,添加以下代码:

  1. public void ConfigureServices(IServiceCollection services)
  1. {
  1. services.AddMvc();
  1. // New code
  1. services.AddSingleton<ITodoRepository, TodoRepository>();
  1. }

应用运行时, 一旦controller被创建,framework 自动注入TodoRepository 到controller中,它将作用于整个应用的生命周期。

在IIS外独立部署应用

默认情况下,当你点击F5,应用会在IIS Express中运行。你可以在工具栏中看到IIS Express 图标。

ASP.NET 5.0 可以部署到不同的服务器中,在本节中,我们将使用可运行在IIS外的WebListener。

注意:将应用部署在IIS中仍有诸多的优势,例如安全性、进度管理等。

在project.json 文件,添加Microsoft.AspNet.Server.WebListener 包:

  1. "dependencies": {
  1. "Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
  1. "Microsoft.AspNet.Diagnostics": "1.0.0-beta1",
  1. "Microsoft.AspNet.Mvc": "6.0.0-beta1",
  1. // New:
  1. "Microsoft.AspNet.Server.WebListener": "6.0.0-beta1"
  1. },

接下来添加以下选项到project.json。

  1. {
  1. // Other sections not shown
  1.  
  1. "commands": {
  1. "web ": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
  1. }
  1. }

“commands” 中包含了可以传递给K 运行时的预定义指令列表。在这个例子中, “web” 是指令名称,它可以是任意实际指令名称值。

Microsoft.AspNet.Hosting 程序集用于部署ASP.NET 5.0 应用。

· --server 标记用于声明服务器,在这个例子中为WebListener。

· --server.urls 标记提供需要监听的URL。

保存project.json 文件。在Solution Explorer中,右键点击工程选择Properties。在 Properties 栏,点击Debug。在Debug target 下,更改 “IIS Express” 为 “web”。

点击F5运行App。Visual Studio 这时会运行启动WebListener 的控制台应用。

打开浏览器,输入http://localhost:5000。你可以看到欢迎界面。

如果需要使用IIS,在上一步骤中更改Debug Target 为 “IIS Express”即可。

这篇文章为本系列文章的最后一篇,感谢大家的关注。本系列的所有教程旨在帮助大家更好的理解ASP.NET 5,以便更好的进行开发。同时,也可以借助一些开发工具来助力开发过程。ComponentOne Studio for ASP.NET 是ASP.NET平台上的一整套完备的开发工具包,用于在各种浏览器中创建和设计具有现代风格的Web应用程序。

原文链接:http://www.asp.net/vnext/overview/aspnet-vnext/create-a-web-api-with-mvc-6

目录:

ASP.NET 5系列教程(七)完结篇-解读代码的更多相关文章

  1. 【ASP.NET Identity系列教程(一)】ASP.NET Identity入门

    注:本文是[ASP.NET Identity系列教程]的第一篇.本系列教程详细.完整.深入地介绍了微软的ASP.NET Identity技术,描述了如何运用ASP.NET Identity实现应用程序 ...

  2. 【ASP.NET Identity系列教程(二)】运用ASP.NET Identity

    注:本文是[ASP.NET Identity系列教程]的第二篇.本系列教程详细.完整.深入地介绍了微软的ASP.NET Identity技术,描述了如何运用ASP.NET Identity实现应用程序 ...

  3. 【ASP.NET Identity系列教程(三)】Identity高级技术

    注:本文是[ASP.NET Identity系列教程]的第三篇.本系列教程详细.完整.深入地介绍了微软的ASP.NET Identity技术,描述了如何运用ASP.NET Identity实现应用程序 ...

  4. ASP.NET 5系列教程 (六): 在 MVC6 中创建 Web API

    ASP.NET 5.0 的主要目标之一是统一MVC 和 Web API 框架应用. 接下来几篇文章中您会了解以下内容: ASP.NET MVC 6 中创建简单的web API. 如何从空的项目模板中启 ...

  5. Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇

    Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇 本文主要内容: 1:spring cloud整合Eureka总结 本文是由凯哥(凯哥Java:kagejava ...

  6. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. ASP.NET Identity系列教程(目录)

    $(document).ready(function(){ $("#hide").click(function(){ $(".en").hide(); }); ...

  8. ASP.NET 5系列教程 (四):向视图中添加服务和发布应用到公有云

    向视图中添加服务 现在,ASP.NET MVC 6 支持注入类到视图中,和VC类不同的是,对类是公开的.非嵌套或非抽象并没有限制.在这个例子中,我们创建了一个简单的类,用于统计代办事件.已完成事件和平 ...

  9. 黄聪:Microsoft Enterprise Library 5.0 系列教程(七) Exception Handling Application Block

    原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(七) Exception Handling Application Block 使用企业库异常处理应用程序模块的 ...

随机推荐

  1. C# XSD校验XML文件的代码

    /// <summary> /// XSD文件校验XML /// </summary> /// <returns></returns> public A ...

  2. Xshell

    http://baike.baidu.com/link?url=5lc5IxVVauitYSbqlOXJBvrvM3qVfMhzz6x_xu2cOMb108Ln9Wk7iJ3f46vG0kBninKw ...

  3. poj 2337 有向图输出欧拉路径

    Catenyms Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10186   Accepted: 2650 Descrip ...

  4. ViewPager图片轮转带点的

    布局页面设置: <?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:and ...

  5. ( 解压缩版 免安装版 或 zip版 )如何修改mysql5.6.24 字符编码

    1.当我们把zip文件格式解压到指定目录后,并且完成基本环境配置后,打开mysql 5.6.24会发现名为[my-default.ini]的文件.我们用记事本打开该文件会发现并没有[default-c ...

  6. Swift3.0基础语法学习<四>

    协议和扩展: // // ViewController4.swift // SwiftBasicDemo // // Created by 思 彭 on 16/11/16. // Copyright ...

  7. JVM 基础知识

    JVM 基础知识(GC) 2013-12-10 00:16 3190人阅读 评论(1) 收藏 举报 分类: Java(49) 目录(?)[+] 几年前写过一篇关于JVM调优的文章,前段时间拿出来看了看 ...

  8. 【使用git】初识git

    0. 版本控制 版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修改情况的系统(vcs). svn等是集中式版本控制,即服务器在单一机器上,每次checkout变化的文件,若机器故障,则有可能 ...

  9. JS-字符串操作,查找显示高亮

    <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content=&q ...

  10. Jade之Code

    Code jade支持内嵌js的代码到jade代码之中. Unbuffered Code 无缓冲代码以-符号开始,无任何额外输出(文本是什么即是什么). jade: - for (var x = 0; ...