您的位置:首页 > 其它

Create a Web API in MVC 6

2015-02-25 17:28 232 查看
原文: 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语句. using
Microsoft.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/todoReturns all ToDo items
GET /api/todo/idReturns the ToDo item with the ID given in the URL.
POST /api/todoCreates a new ToDo item. The client sends the ToDo item in the request body.
DELETE /api/todo/idDeletes 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[/code] 但是下面的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和匹配的对应的控制器方法:

RequestController Action
GET /api/todoGetAll
POST /api/todoCreateTodoItem
GET /api/todo/1GetById
DELETE /api/todo/1DeleteItem
GET /api/todo/abcnone – returns 404
PUT /api/todonone – 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:5000Accept: 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
:[/code]

[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
, 在整个应用程序的生命周期中会使用同一个实例.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐