[译]Create a Web API in MVC 6
原文: http://www.asp.net/vnext/overview/aspnet-vnext/create-a-web-api-with-mvc-6
ASP.NET 5.0的一个目标是合并MVC和Web API frameworkd.
创建空白ASP.NET 5项目
打开Visual Studio 2015. 在File菜单, 选择 New > Project.
在New Project对话框中, 点击Templates > Visual C# > Web, 选择ASP.NET Web Application项目模板. 起名为 "TodoApi" .
在New ASP.NET Project对话框中, 选择"ASP.NET 5.0 Empty"模板.
下面的图片显示了项目的结构.
项目包括下面的文件:
- global.json包含解决方案级别的设置, 包含了项目之间的依赖关系.
- project.json包含项目的配置.
- Project_Readme.html是一个readme文件.
- Startup.cs 包含了startup和配置代码.
Startup
类定义在Startup.cs文件中, 配置了ASP.NET请求管道. 当你使用了空白的项目模板, Startup
class 基本上不包含什么代码添加请求管道:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
// Nothing here!
}
}
现在就可以运行程序了, 但是他不包含任何功能. 如果使用"Starter Web" 模板,会自己默认就配置了一些框架,例如MVC 6, Entity Framework, authentication, logging等.
添加欢迎页面
打开project.json文件. 这个文件包含了项目的一些配置. dependencies
部分列出了项目需要的NuGet包和类库. 添加Microsoft.AspNet.Diagnostics包:
"dependencies": {
"Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
// Add this:
"Microsoft.AspNet.Diagnostics": "1.0.0-beta1"
},
当你在输入的时候, Visual Studio的智能提示会列出一些NuGet包.
智能提示也会提供包的版本号:
接下来, 打开Startup.cs添加下面的代码.
using System;
using Microsoft.AspNet.Builder; namespace TodoApi
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
// New code
app.UseWelcomePage();
}
}
}
按F5后你会看到类似于下面的一个欢迎页面:
创建Web API
创建一个web API管理ToDo条目. 首先添加ASP.NET MVC 6.
在project.json的dependencies的section添加MVC 6包:
"dependencies": {
"Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
"Microsoft.AspNet.Diagnostics": "1.0.0-beta1",
// New:
"Microsoft.AspNet.Mvc": "6.0.0-beta1"
},
下一步添加MVC请求管道. 在Startup.cs中,
- 添加
using
statement语句. usingMicrosoft.Framework.DependencyInjection
- 在
Startup
类中添加下面的方法.public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}上面的代码添加了所有MVC6需要的依赖. 项目启动的时候会自动调用
ConfigureServices
. - 在Configure方法中, 添加下面的代码.
UseMvc
方法添加MVC 6到请求管道.public void Configure(IApplicationBuilder app)
{
// New:
app.UseMvc();
}
下面是完整的Startup
类:
using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
// New using:
using Microsoft.Framework.DependencyInjection; namespace TodoApi
{
public class Startup
{
// Add this method:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
} public void Configure(IApplicationBuilder app)
{
// New:
app.UseMvc();
app.UseWelcomePage();
}
}
}
添加模型
using System.ComponentModel.DataAnnotations; namespace TodoApi.Models
{
public class TodoItem
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
public bool IsDone { get; set; }
}
}
添加控制器
using Microsoft.AspNet.Mvc;
using System.Collections.Generic;
using System.Linq;
using TodoApi.Models; namespace TodoApi.Controllers
{ [Route("api/[controller]")]
public class TodoController : Controller
{
static readonly List<TodoItem> _items = new List<TodoItem>()
{
new TodoItem { Id = 1, Title = "First Item" }
}; [HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _items;
} [HttpGet("{id:int}", Name = "GetByIdRoute")]
public IActionResult GetById (int id)
{
var item = _items.FirstOrDefault(x => x.Id == id);
if (item == null)
{
return HttpNotFound();
} return new ObjectResult(item);
} [HttpPost]
public void CreateTodoItem([FromBody] TodoItem item)
{
if (!ModelState.IsValid)
{
Context.Response.StatusCode = 400;
}
else
{
item.Id = 1+ _items.Max(x => (int?)x.Id) ?? 0;
_items.Add(item); string url = Url.RouteUrl("GetByIdRoute", new { id = item.Id },
Request.Scheme, Request.Host.ToUriComponent()); Context.Response.StatusCode = 201;
Context.Response.Headers["Location"] = url;
}
} [HttpDelete("{id}")]
public IActionResult DeleteItem(int id)
{
var item = _items.FirstOrDefault(x => x.Id == id);
if (item == null)
{
return HttpNotFound();
}
_items.Remove(item);
return new HttpStatusCodeResult(204); // 201 No Content
}
}
}
上面的控制器实行了基本的增删改查操作:
Request (HTTP method + URL) | Description |
---|---|
GET /api/todo | Returns all ToDo items |
GET /api/todo/id | Returns the ToDo item with the ID given in the URL. |
POST /api/todo | Creates a new ToDo item. The client sends the ToDo item in the request body. |
DELETE /api/todo/id | Deletes a ToDo item. |
请求:
GET http://localhost:5000/api/todo HTTP/1.1
User-Agent: Fiddler
Host: localhost:5000
响应:
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 30 Oct 2014 22:40:31 GMT
Content-Length: 46 [{"Id":1,"Title":"First Item","IsDone":false}]
解释代码
Routing路由
[Route] attribute 定义了这个控制器URL模板:
[Route("api/[controller]")]
在上面的例子中“[controller]” 替代controller的类名, 减去“Controller”后缀. api/todo匹配TodoController
控制器.
HTTP 方法
[HttpGet], [HttpPost] and [HttpDelete] attributes 定义了action的Http方法
[HttpGet]
public IEnumerable<TodoItem> GetAll() {} [HttpGet("{id:int}", Name = "GetByIdRoute")]
public IActionResult GetById (int id) {} [HttpPost]
public void CreateTodoItem([FromBody] TodoItem item) {} [HttpDelete("{id:int}")]
public IActionResult DeleteItem(int id) {}
在上面的例子中 GetById
和 DeleteItem
, 的定义了参数. 完整的路由模板是“api/[controller]/{id:int}”.
在 “{id:int}” 片段中, id是一个参数, and “:int”限制了参数的类型是整形. 下面的URL会被匹配:
http://localhost/api/todo/1
http://localhost/api/todo/42
但是下面的URL不会匹配:
http://localhost/api/todo/abc
注意GetById
和 DeleteItem
同样也有一个方法参数名为id. 例如, http://localhost/api/todo/42
, id的值会被设置为42.
CreateTodoItem
方法展示了另外一种形式的参数绑定:
[HttpPost]
public void CreateTodoItem([FromBody] TodoItem item) {}
[FromBody] attribute告诉框架会将请求内容序列会为TodoItem
参数.
下面展示了请求URL和匹配的对应的控制器方法:
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 |
Action的返回值
TodoController
展示了几种不同的返回值.
GetAll
方法返回一个CLR对象.
[HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _items;
}
默认返回值是JSON, 但是用户可以请求其它的格式. 例如, 下面请求一个XML响应.
GET http://localhost:5000/api/todo HTTP/1.1
User-Agent: Fiddler
Host: localhost:5000
Accept: application/xml
Response:
HTTP/1.1 200 OK
Content-Type: application/xml;charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 30 Oct 2014 22:40:10 GMT
Content-Length: 228 <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
:
[HttpGet("{id:int}", Name = "GetByIdRoute")]
public IActionResult GetById (int id)
{
var item = _items.FirstOrDefault(x => x.Id == id);
if (item == null)
{
return HttpNotFound();
} return new ObjectResult(item);
}
如果没有找到对应的todo, 返回HttpNotFound
.
最后, CreateTodoItem
展示如何直接修改reponse的属性返回.
[HttpPost]
public void CreateTodoItem([FromBody] TodoItem item)
{
// (some code not shown here) Context.Response.StatusCode = 201;
Context.Response.Headers["Location"] = url;
}
依赖注入
MVC 6直接把依赖注入集成在了框架中:
using System.Collections.Generic; namespace TodoApi.Models
{
public interface ITodoRepository
{
IEnumerable<TodoItem> AllItems { get; }
void Add(TodoItem item);
TodoItem GetById(int id);
bool TryDelete(int id);
}
}
实现.
using System;
using System.Collections.Generic;
using System.Linq; namespace TodoApi.Models
{
public class TodoRepository : ITodoRepository
{
readonly List<TodoItem> _items = new List<TodoItem>(); public IEnumerable<TodoItem> AllItems
{
get
{
return _items;
}
} public TodoItem GetById(int id)
{
return _items.FirstOrDefault(x => x.Id == id);
} public void Add(TodoItem item)
{
item.Id = 1 + _items.Max(x => (int?)x.Id) ?? 0;
_items.Add(item);
} public bool TryDelete(int id)
{
var item = GetById(id);
if (item == null)
{
return false;
}
_items.Remove(item);
return true;
}
}
}
在控制器中使用构造函数依赖注入:
[Route("api/[controller]")]
public class TodoController : Controller
{
// Remove this code:
//static readonly List<TodoItem> _items = new List<TodoItem>()
//{
// new TodoItem { Id = 1, Title = "First Item" }
//}; // Add this code:
private readonly ITodoRepository _repository; public TodoController(ITodoRepository repository)
{
_repository = repository;
}
更新代码使用仓储操作数据:
[HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _repository.AllItems;
}
[HttpGet("{id:int}", Name = "GetByIdRoute")]
public IActionResult GetById(int id)
{
var item = _repository.GetById(id);
if (item == null)
{
return HttpNotFound();
} return new ObjectResult(item);
} [HttpPost]
public void CreateTodoItem([FromBody] TodoItem item)
{
if (!ModelState.IsValid)
{
Context.Response.StatusCode = 400;
}
else
{
_repository.Add(item); string url = Url.RouteUrl("GetByIdRoute", new { id = item.Id }, Request.Scheme, Request.Host.ToUriComponent());
Context.Response.StatusCode = 201;
Context.Response.Headers["Location"] = url;
}
} [HttpDelete("{id}")]
public IActionResult DeleteItem(int id)
{
if (_repository.TryDelete(id))
{
return new HttpStatusCodeResult(204); // 201 No Content
}
else
{
return HttpNotFound();
}
}
为了依赖注入能正常的工作, 我们需要注册仓储到依赖注入系统. 在Startup
类中, 添加下面的代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// New code
services.AddSingleton<ITodoRepository, TodoRepository>();
}
当应用运行的时候,框架会自动将TodoRepository
注入到控制器. 因为我们使用AddSingleton
注册ITodoRepository
, 在整个应用程序的生命周期中会使用同一个实例.
[译]Create a Web API in MVC 6的更多相关文章
- 002.Create a web API with ASP.NET Core MVC and Visual Studio for Windows -- 【在windows上用vs与asp.net core mvc 创建一个 web api 程序】
Create a web API with ASP.NET Core MVC and Visual Studio for Windows 在windows上用vs与asp.net core mvc 创 ...
- YbSoftwareFactory 代码生成插件【二十一】:Web Api及MVC性能提升的几个小技巧
最近在进行 YbSoftwareFactory 的流程功能升级,目前已经基本完成,现将用到的一些关于 Web Api 及 MVC 性能提升的一些小技巧进行了总结,这些技巧在使用.配置上也相当的简单,但 ...
- Entity Framework 6 Recipes 2nd Edition(9-3)译->找出Web API中发生了什么变化
9-3. 找出Web API中发生了什么变化 问题 想通过基于REST的Web API服务对数据库进行插入,删除和修改对象图,而不必为每个实体类编写单独的更新方法. 此外, 用EF6的Code Fri ...
- web api与mvc的区别
MVC主要用来构建网站,既关心数据也关心页面展示,而Web API只关注数据 Web API支持格式协商,客户端可以通过Accept header通知服务器期望的格式 Web API支持Self Ho ...
- Web API与MVC控制器的区别
Web API属于ASP.NET核心平台的一部分,它利用MVC框架的底层功能方便我们快速的开发部署WEB服务.我们可以在常规MVC应用通过添加API控制器来创建web api服务,普通MVC应用程序控 ...
- ASP.NET 5系列教程 (六): 在 MVC6 中创建 Web API
ASP.NET 5.0 的主要目标之一是统一MVC 和 Web API 框架应用. 接下来几篇文章中您会了解以下内容: ASP.NET MVC 6 中创建简单的web API. 如何从空的项目模板中启 ...
- 在 MVC6 中创建 Web API
ASP.NET 5系列教程 (六): 在 MVC6 中创建 Web API ASP.NET 5.0 的主要目标之一是统一MVC 和 Web API 框架应用. 接下来几篇文章中您会了解以下内容: ...
- 【ASP.NET MVC 5】第27章 Web API与单页应用程序
注:<精通ASP.NET MVC 3框架>受到了出版社和广大读者的充分肯定,这让本人深感欣慰.目前该书的第4版不日即将出版,现在又已开始第5版的翻译,这里先贴出该书的最后一章译稿,仅供大家 ...
- Asp.Net Web API VS Asp.Net MVC
http://www.dotnet-tricks.com/Tutorial/webapi/Y95G050413-Difference-between-ASP.NET-MVC-and-ASP.NET-W ...
随机推荐
- android逆向学习小结--CrackMe_1
断断续续的总算的把android开发和逆向的这两本书看完了,虽然没有java,和android开发的基础,但总体感觉起来还是比较能接收的,毕竟都是触类旁通的.当然要深入的话还需要对这门语言的细节特性和 ...
- shell命令locate
介绍 linux上做维护的时候经常会去查找某个文件路径 如果不需要特殊的查找匹配(比如时间 大小...) 格式化的输出(此处用find) 建议用locate命令 因为locate命令查找速度非常的快 ...
- iOS 即时通讯SDK的集成,快速搭建自己的聊天系统
现在的外包项目需求变态的各种各样,今天要做社交,明天要加电商,后天又要加直播了,这些系统如果要自己开发,除非大公司技术和人力都够,不然短时间是几乎实现不了的.所以学会灵活利用市面上的各种SDK是灰常重 ...
- POJ 2828 Buy Tickets(线段树 树状数组/单点更新)
题目链接: 传送门 Buy Tickets Time Limit: 4000MS Memory Limit: 65536K Description Railway tickets were d ...
- 强大的windbg定位内存泄露,两句命令搞定!
1.简单配置在windbg程序目录下有个gflags.exe,运行后设置: 运行CMD.EXE,输入"D:\Debugging Tools for Windows (x86)\gflags. ...
- MySql中时间比较的实现
unix_timestamp 函数可以接受一个参数,也可以不使用参数.它的返回值是一个无符号的整数.不使用参数,它返回自1970年1月1日0时0分0秒到现在所经过的秒数,如果 使用参数,参数的 ...
- Nginx系列1之部分模块详解
1 内核模块: 名称: daemon 语法: daemon on |off 默认值: on 功能: 决定nginx 在前台执行还是后台守护进程执行的 ================== 名称: En ...
- Linux 常用命令笔记 (持续更新)
声明:本文是转载前辈的,地址:http://www.cnblogs.com/tovep/articles/2473147.html 在tomcat的bin目录下执行 ./shutdown.sh 为了查 ...
- js024-最佳实践
js024-最佳实践 本章内容: 可维护的代码 保证代码性能 部署代码 24.1 可维护性 24.1.1 代码的可维护性 代码可维护性的特征: 特性 说明 可理解性 其他人可以理解它的用途和一般途径 ...
- ubuntu下怎么解决python "Non-ASCII character"错误
解决方法:源代码文件第一行添加:#coding:utf-8 参考: http://jingyan.baidu.com/album/219f4bf7d04887de442d3899.html?pici ...