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中,

  1. 添加using statement语句. using Microsoft.Framework.DependencyInjection
  2. Startup类中添加下面的方法.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    }

    上面的代码添加了所有MVC6需要的依赖. 项目启动的时候会自动调用ConfigureServices.

  3. 在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, 在整个应用程序的生命周期中会使用同一个实例.

时间: 2024-10-10 02:41:05

Create a Web API in MVC 6的相关文章

YbSoftwareFactory 代码生成插件【二十一】:Web Api及MVC性能提升的几个小技巧

最近在进行 YbSoftwareFactory 的流程功能升级,目前已经基本完成,现将用到的一些关于 Web Api 及 MVC 性能提升的一些小技巧进行了总结,这些技巧在使用.配置上也相当的简单,但通常都能大大提高应用程序的性能,希望对大家有用. 一.缓存 为了避免每次请求都去访问后台的资源,我们一般会考虑将一些更新不是很频繁的,可以重用的数据,通过一定的方式临时地保存起来,后续的请求根据情况可以直接访问这些保存起来的数据,这种机制就是所谓的缓存机制.缓存分为页面输出缓存,内存数据缓存和缓存依

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

ASP.NET 5.0 的主要目标之一是统一MVC 和 Web API 框架应用. 接下来几篇文章中您会了解以下内容: ASP.NET MVC 6 中创建简单的web API. 如何从空的项目模板中启动,及添加控件到应用中. 如何配置 ASP.NET 5.0 管道. 在 IIS 外对立部署应用. 本文的目的是从空的项目开始,逐步讲解如何创建应用.当然,您也可以从“Starter Web” 模板开始,它默认包含了MVC 6.权限.记录等其他模块,同时也内置了有效的控制器和视图在其中. 创建空的 A

Asp.Net Web API VS Asp.Net MVC

http://www.dotnet-tricks.com/Tutorial/webapi/Y95G050413-Difference-between-ASP.NET-MVC-and-ASP.NET-Web-API.html Asp.Net MVC is used to create web applications that returns both views and data but Asp.Net Web API is used to create full blown HTTP serv

[ASP.NET MVC 小牛之路]18 - Web API

原文:[ASP.NET MVC 小牛之路]18 - Web API Web API 是ASP.NET平台新加的一个特性,它可以简单快速地创建Web服务为HTTP客户端提供API.Web API 使用的基础库是和一般的MVC框架一样的,但Web API并不是MVC框架的一部分,微软把Web API相关的类从 System.Web.Mvc 命名空间下提取了出来放在 System.Web.Http 命名空间下.这种理念是把 Web API 作为ASP.NET 平台的核心之一,以使Web API能使用在

OWIN support for the Web API 2 and MVC 5 integrations in Autofac

Currently, in the both the Web API and MVC frameworks, dependency injection support does not come into play until after the OWIN pipeline has started executing. This is simply a result of the OWIN support being added to both frameworks after their in

初试ASP.NET Web API/MVC API(附Demo)

参考页面: http://www.yuanjiaocheng.net/webapi/media-formatter.html http://www.yuanjiaocheng.net/webapi/webapi-filters.html http://www.yuanjiaocheng.net/webapi/create-crud-api-1.html http://www.yuanjiaocheng.net/webapi/create-crud-api-1-get.html http://ww

Asp.net MVC 与 Asp.net Web API 区别

Asp.Net Web API VS Asp.Net MVC 1.Asp.net MVC 是用来创建返回视图(Views)与数据的Web应用,而Asp.net Web API是一种简单轻松地成熟的HTTP服务,它只返回数据,不返回视图(Views). 2.Asp.net Web API可以通过.Net Framework来帮助我们构建REST-ful服务,而且他支持内容协商(根据客户端能接受的格式要求,返回相应的JSON,XML,ATOM),同时Asp.net Web API支持自我宿主(sel

既生瑜何生亮?ASP.NET MVC VS ASP.NET Web API

Asp.net MVC 与 Asp.net Web API 区别 在我们开发一些web应用时,我们一样可以在MVC Framework 中使用JsonResult 来返回JSON数据,同样也可以处理一下简单的AJAX请求,那么为何微软又推出Web API这么个东西呢?接下来我们来比较一下.二者(Asp.net MVC 与 Asp.net Web Api)何时用? Asp.Net Web API VS Asp.Net MVC 1.Asp.net MVC 是用来创建返回视图(Views)与数据的We

Swagger UI教程 API 文档神器 搭配Node使用 web api 接口文档 mvc接口文档

两种方案 一.Swagger 配置 web Api 接口文档美化 二.通过NodeJS 发布Swagger UI 配置api 文档 先说一下简单的 Swagger 配置 web Api  Swagger-UI本身只提供在线测试功能,要集成它还需要告诉它本项目提供的各种服务和参数信息.这里就需要一些工作量了,不过好在许多第三方库已经给我们完成了这一工作.我这里用的是Swashbuckle,使用它也比较简单,直接使用Nuget添加其程序包即可: 1.初始化包  PM> Install-Package