• [译]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和匹配的对应的控制器方法:

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

  • 相关阅读:
    20175311 2018-2019-2 《Java程序设计》第7周学习总结
    20175311胡济栋 2018-2019-2《Java程序设计》结对编程项目-四则运算 第一周 阶段性总结
    20175314 《信息安全系统设计基础》课程总结
    USCOSII
    改进ls的实现
    cat userlist
    实现ls
    stat命令的实现-mysate
    实现mypwd
    2019-2020-1 20175314_20175316 实验五 通讯协议设计
  • 原文地址:https://www.cnblogs.com/irocker/p/create-a-web-api-with-mvc-6.html
Copyright © 2020-2023  润新知