【ASP.NET Core学习】Web API

这里介绍在ASP.NET Core中使用Web API创建 RESTful 服务,本文使用VSCode + NET Core3.0

  1. 创建简单Rest API
  2. 格式化输出
  3. JSON Patch请求
  4. Open API(Swagger)集成

创建简单Rest API

在终端输入

dotnet new webapi -n WebAPI

1. 创建Order模型,然后初始化数据

public class OrderStore
{
    public List<Order> Orders { get; } = new List<Order>();

    public OrderStore()
    {
        var random = new Random();
        foreach (var item in Enumerable.Range(1, 10))
        {
            Orders.Add(new Order
            {
                Id = item,
                OrderNo = DateTime.Now.AddSeconds(random.Next(100, 200)).AddMilliseconds(random.Next(20, 50)).Ticks.ToString(),
                Quantity = random.Next(1, 10),
                Amount = Math.Round(((decimal)random.Next(100, 500) / random.Next(2, 6)), 2)
            });
        }
    }
}

2. 简单REST API接口

/// <summary>
/// 订单模块
/// </summary>
[ApiController]
[Route("[controller]")]
[FormatFilter]
public class OrderController : ControllerBase
{

    readonly Models.OrderStore _orderStore = null;
    public OrderController(Models.OrderStore orderStore)
    {
        _orderStore = orderStore;
    }

    /// <summary>
    /// 查询所有订单
    /// </summary>
    [HttpGet]
    public ActionResult<List<Models.Order>> GetAll() => _orderStore.Orders;

    /// <summary>
    /// 获取订单
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id:int}.{format?}")]
    public ActionResult<Models.Order> GetById(int id)
    {
        var order = _orderStore.Orders.FirstOrDefault(m => m.Id == id);

        if (order == null)
        {
            return NotFound();
        }

        return order;
    }

    /// <summary>
    /// 创建订单
    /// </summary>
    /// <param name="order"></param>
    /// <returns>成功返回订单Id,失败返回-1</returns>
    [HttpPost]
    public ActionResult<int> Create(Models.Order order)
    {
        if (_orderStore.Orders.Any(m => m.OrderNo == order.OrderNo))
        {
            return -1;
        }

        order.Id = _orderStore.Orders.Max(m => m.Id) + 1;
        _orderStore.Orders.Add(order);

        return order.Id;
    }

    /// <summary>
    /// 更新订单
    /// </summary>
    /// <returns></returns>
    [HttpPut]
    public ActionResult<bool> Update(Models.Order model)
    {
        Console.WriteLine($"OrderNo:{model.OrderNo}");
        var order = _orderStore.Orders.FirstOrDefault(m => m.OrderNo == model.OrderNo);

        if (order == null)
        {
            return NotFound();
        }

        order.Amount = model.Amount;
        order.Quantity = model.Quantity;

        return true;
    }

    /// <summary>
    /// 更新订单指定信息
    /// </summary>
    /// <remarks>
    /// Sample request:
    ///
    ///     PATCH  /Order/{orderNo}
    ///     [
    ///         {
    ///             "op": "test",
    ///             "path": "/quantity",
    ///             "value": "2"
    ///         },
    ///         {
    ///             "op": "test",
    ///             "path": "/amount",
    ///             "value": "38.28"
    ///         },
    ///         {
    ///             "op": "add",
    ///             "path": "/isComplete",
    ///             "value": "true"
    ///         },
    ///     ]
    /// </remarks>
    /// <returns>返回是否成功</returns>
    /// <response code="200">提交成功</response>
    /// <response code="400">提交参数异常</response>
    /// <response code="404">订单号不存在</response>
    [HttpPatch("{orderNo:length(18)}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public ActionResult<bool> Update([FromBody] JsonPatchDocument<Models.Order> patchDoc, [FromRoute] string orderNo)
    {
        var order = _orderStore.Orders.FirstOrDefault(m => m.OrderNo == orderNo);

        if (order == null)
        {
            return NotFound();
        }

        patchDoc.ApplyTo(order, ModelState);

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        return Ok(true);
    }
}

3. 推荐一个VS Code插件(REST Client)测试接口,官方介绍

@baseUrl = https://localhost:5001

###
GET {{baseUrl}}/Order HTTP/1.1

###
# @name order
POST {{baseUrl}}/Order HTTP/1.1
Accept: application/json
Content-Type: application/json

{
    "OrderNo": "637109312996909246",
    "Quantity": 2,
    "Amount": 38.28
}

### 

@orderId = {{order.response.body.*}}
GET {{baseUrl}}/Order/{{orderId}}.json HTTP/1.1

###
GET {{baseUrl}}/Order/{{orderId}}.xml HTTP/1.1
###
GET {{baseUrl}}/Order/{{orderId}} HTTP/1.1
###

PUT {{baseUrl}}/Order HTTP/1.1
Content-Type: application/json
Accept: application/json

{
    "Id": 12,
    "OrderNo": "2019112235759329",
    "Quantity": 2,
    "Amount": 38.28
}

###

GET {{baseUrl}}/Order/11

###

PATCH  {{baseUrl}}/Order/637109312996909246 HTTP/1.1
Accept: application/json
Content-Type: application/json

[
  {
    "op": "test",
    "path": "/quantity",
    "value": "2"
  },
  {
    "op": "test",
    "path": "/amount",
    "value": "38.28"
  },
  {
    "op": "add",
    "path": "/isComplete",
    "value": "true"
  },
]

Sample request:

PATCH  /Order/{orderNo} 

[
  {
    "op": "test",
    "path": "/quantity",
    "value": "2"
  },
  {
    "op": "test",
    "path": "/amount",
    "value": "38.28"
  },
  {
    "op": "add",
    "path": "/isComplete",
    "value": "true"
  },
]

简单介绍一下,

文件后缀是http 或 rest

定义全局变量:@baseUrl = https://localhost:5001   ,注意链接不加引号

### 分割多个请求

POST/PUT 请求紧跟Head请求信息,换行加上请求内容

Ctrl + Alt + R 快捷键 / 点Send Request发起请求

格式化输出

Api接口通常会是不同客户端调用,这样会有可能出现需要不同响应格式,例如常用的Json,XML。

ASPNET Core 默认情况下是忽略 Accept 标头,JSON格式返回

一、支持XML格式

1. 添加xml格式化

services.AddControllers(options =>
    {
        options.RespectBrowserAcceptHeader = true;  //接受浏览器标头
    })
    .AddXmlSerializerFormatters();                   //添加XMl格式化
}

2. 请求是添加标头

@orderId = {{order.response.body.*}}
GET {{baseUrl}}/Order/{{orderId}} HTTP/1.1
Accept: text/xml

若不添加标头,默认使用JSON格式输出

二、URL格式映射

1. 添加[FormatFilter]过滤器,它会检查路由中格式是否存在,并且使用相应的格式化程序输出

2. 路由规则添加{format?}

[HttpGet("{id:int}.{format?}")]
public ActionResult<Models.Order> GetById(int id)
{
    var order = _orderStore.Orders.FirstOrDefault(m => m.Id == id);

    if (order == null)
    {
        return NotFound();
    }

    return order;
}

Url 响应

GET {{baseUrl}}/Order/{{orderId}} HTTP/1.1
JSON(若配置格式化输出)

GET {{baseUrl}}/Order/{{orderId}}.xml
XML(若配置格式化输出)

GET {{baseUrl}}/Order/{{orderId}}.json

JSON(若配置格式化输出)

三、添加基于 Newtonsoft.Json 的 JSON 格式支持

在ASPNET Core 3.0开始,不再使用Newtonsoft.Json格式化JSON,而是使用System.Text.Json格式化,我们可以替换成Newtonsoft.Json

1. 添加包

dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson

2. 配置Newtonsoft.Json

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson(options =>                   //添加基于NewtonsoftJson格式化
        {
            options.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
            options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
        });
}

JSON Patch请求

PUT 和 PATCH 方法用于更新现有资源。 它们之间的区别是,PUT 会替换整个资源,而PATCH 仅指定更改。

什么是JSON Patch?

JSON Patch官网 里面有一句介绍的很清楚:JSON Patch is a format for describing changes to a JSON document. (一种描述Json的变化的格式)

什么时候需要用到JSON Patch

  1. 我们返回的JSON很大,修改可能只是某些字段
  2. 对性能要求比较大的地方
  3. 一个大的对象,好几个地方修改,然后统一接口修改

ASPNET Core如何处理JSON Patch 请求

1. 添加包支持

dotnet add package Microsoft.AspNetCore.JsonPatch

2. 使用 HttpPatch 属性进行批注

3. 接受 JsonPatchDocument<T>,通常带有 [FromBody]

4. 调用 ApplyTo 以应用更改

假设我们现在有一个完成订单的需求

  1. 检查金额,数量是否有变更
  2. 更新IsComplete = true

下面附上代码和提交的JSON

控制器代码

[HttpPatch("{orderNo:length(18)}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<bool> Update([FromBody] JsonPatchDocument<Models.Order> patchDoc, [FromRoute] string orderNo)
{
    var order = _orderStore.Orders.FirstOrDefault(m => m.OrderNo == orderNo);

    if (order == null)
    {
        return NotFound();
    }

    patchDoc.ApplyTo(order, ModelState);

    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    return Ok(true);
}

失败的JSON(金额校验不过)

PATCH  {{baseUrl}}/Order/637109312996909246 HTTP/1.1
Accept: application/json
Content-Type: application/json

[
  {
    "op": "test",
    "path": "/quantity",
    "value": "2"
  },
  {
    "op": "test",
    "path": "/amount",
    "value": "38.28"
  },
  {
    "op": "add",
    "path": "/isComplete",
    "value": "true"
  },
]

会在ModelState里面列出校验不过的信息

成功的JSON

PATCH  {{baseUrl}}/Order/637109312996909246 HTTP/1.1
Accept: application/json
Content-Type: application/json

[
  {
    "op": "test",
    "path": "/quantity",
    "value": "2"
  },
  {
    "op": "test",
    "path": "/amount",
    "value": "36.8"
  },
  {
    "op": "add",
    "path": "/isComplete",
    "value": "true"
  },
]

我们用Get请求重新查一下,可以看到IsComplete成功被修改了

这里只是简单介绍JSON Patch使用,更多使用方法参考JSON Pan官网微软文档

Open API(Swagger)集成

Api 通常需要跟客户端,前端进行沟通,需要编写文档,这需要花费大量时间。

Open Api是专门解决这种问题,它为RESTful api定义了一个标准的、与语言无关的接口,利用工具生成文档,可以做到代码即文档(逼着开发者完善注释)

ASPNET Core 可以使用Swashbuckle.AspNetCoreNSwag 生成Swagger 文档

下面介绍如何使用Swashbuckle.AspNetCore

一、使用Swashbuckle.AspNetCore

  1. 安装Swashbuckle.AspNetCore包

    dotnet add package Swashbuckle.AspNetCore
  2. 添加并配置 Swagger 中间件

    引用命名空间:using Microsoft.OpenApi.Models;

    services.AddSingleton<Models.OrderStore>();
    
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "Web Api Doc", Version = "v1" });
    });
    app.UseSwagger();
    
    app.UseSwaggerUI(c =>
    {
      c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });

     经过上面两步就可以使用SwaggerUI来查看文档和测试,浏览器打开(http://{url}/swagger)

二、添加XML注释

上面生成的Swagger文档是不包含XML注释,下面介绍如何添加XML注释

  1. 项目文件(*.csproj)添加以下

    <PropertyGroup>

    <GenerateDocumentationFile>true</GenerateDocumentationFile>

    <NoWarn>$(NoWarn);1591</NoWarn>

    </PropertyGroup>

    加上上面生成文档后,未注释的函数,属性会发出警告,警告代码1591,忽略警告可以添加多个,分号分割

  2. AddSwaggerGen添加下面XML支持

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "Web Api Doc", Version = "v1" });
    
        var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
        var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
        c.IncludeXmlComments(xmlPath);
    });
  3. 方法添加注释

    /// <summary>
    /// 更新订单指定信息
    /// </summary>
    /// <remarks>
    /// Sample request:
    ///
    ///     PATCH  /Order/{orderNo}
    ///     [
    ///         {
    ///             "op": "test",
    ///             "path": "/quantity",
    ///             "value": "2"
    ///         },
    ///         {
    ///             "op": "test",
    ///             "path": "/amount",
    ///             "value": "38.28"
    ///         },
    ///         {
    ///             "op": "add",
    ///             "path": "/isComplete",
    ///             "value": "true"
    ///         },
    ///     ]
    /// </remarks>
    /// <returns>返回是否成功</returns>
    /// <response code="200">提交成功</response>
    /// <response code="400">提交参数异常</response>
    /// <response code="404">订单号不存在</response>

    ProducesResponseType 描述返回类型

    remarks 会生成请求说明

  4. 效果

Web Api 使用就介绍这些,如有错漏,希望指出。

转发请标明出处:https://www.cnblogs.com/WilsonPan/p/11945856.html

示例代码:https://github.com/WilsonPan/AspNetCoreExamples/tree/master/WebApi

原文地址:https://www.cnblogs.com/WilsonPan/p/11945856.html

时间: 2024-11-05 20:38:28

【ASP.NET Core学习】Web API的相关文章

基于ASP.NET Core 创建 Web API

使用 Visual Studio 创建项目. 文件->新建->项目,选择创建 ASP.NET Core Web 应用程序. 基于 ASP.NET Core 2.0 ,选择API,身份验证选择:不进行身份验证. 至此,就完成了一个ASP.NET Core项目的创建,项目中已经默认创建了一个ValuesController,F5运行项目,可以在浏览器调用已经存在的API. 参考资料: ASP.NET Core 中文文档 第二章 指南(2)用 Visual Studio 和 ASP.NET Core

使用angular4和asp.net core 2 web api做个练习项目(三)

第一部分: http://www.cnblogs.com/cgzl/p/7755801.html 第二部分: http://www.cnblogs.com/cgzl/p/7763397.html 后台代码: https://github.com/solenovex/asp.net-core-2.0-web-api-boilerplate 前台代码: https://github.com/solenovex/angular-4-client-panel-app 下面将开发登陆和授权的部分, 这里要

ABP示例程序-使用AngularJs,ASP.NET MVC,Web API和EntityFramework创建N层的单页面Web应用

本片文章翻译自ABP在CodeProject上的一个简单示例程序,网站上的程序是用ABP之前的版本创建的,模板创建界面及工程文档有所改变,本文基于最新的模板创建.通过这个简单的示例可以对ABP有个更深入的了解,每个工程里应该写什么样的代码,代码如何组织以及ABP是如何在工程中发挥作用的. 源文档地址:https://www.codeproject.com/Articles/791740/Using-AngularJs-ASP-NET-MVC-Web-API-and-EntityFram 源码可以

Asp.Net MVC 4 Web API 中的安全认证-使用OAuth

Asp.Net MVC 4 Web API 中的安全认证-使用OAuth 各种语言实现的oauth认证: http://oauth.net/code/ 上一篇文章介绍了如何使用基本的http认证来实现asp.net web api的跨平台安全认证. 这里说明一个如何使用oauth实现的认证.oauth大家可能不陌生.那么这里需要注意的是我们使用的是.net平台一个比较好的开源oauth库. DOTNETOPENAUTH. 就像上图所示,我们需要一个ISSSUE Server来给我们一个token

[Asp.Net] MVC 和Web API 的区别

Asp.net MVC 和web api 的action 在获取从前台传入的数据是有很大不同 前台使用ajax的方式向后台发起post的请求 Content-Type:application/json 使用以下json对象 { "user": { "Username":"xxx", "Password":"xxxx" } } { "Username":"xxx", &

ASP.NET Core学习系列

.NET Core ASP.NET Core ASP.NET Core学习之一 入门简介 ASP.NET Core学习之二 菜鸟踩坑 ASP.NET Core学习之三 NLog日志 ASP.NET Core学习之四 在CentOS上部署.net core LINUX学习系列 DOCKER学习系列 微服务学习系列 原文地址:https://www.cnblogs.com/xcsn/p/8306854.html

ASP.NET Core环境Web Audio API+SingalR+微软语音服务实现web实时语音识别

处于项目需要,我研究了一下web端的语音识别实现.目前市场上语音服务已经非常成熟了,国内的科大讯飞或是国外的微软在这块都可以提供足够优质的服务,对于我们工程应用来说只需要花钱调用接口就行了,难点在于整体web应用的开发.最开始我实现了一个web端录好音然后上传服务端进行语音识别的简单demo,但是这种结构太过简单,对浏览器的负担太重,而且响应慢,交互差:后来经过调研,发现微软的语音服务接口是支持流输入的连续识别的,因此开发重点就在于实现前后端的流式传输.参考这位国外大牛写的博文Continuou

ASP.NET MVC的Web Api的实练

学习ASP.NET MVC一年多来,现在该学学Web Api了.API与ASP.NET MVC的Controller差不多.前者只是返回数据序列化和发送给客户端: 后者返回View或Render View. 当你在专案中创建第一个Web Api时,它会自动产生一个文档和修改了web.config.如我们先在专案下添加一个Apis目录,是用来存放api控制器的.创建完成之后,它会显示一个txt文档: 这个readme.txt是告诉你需要修改Globel.asax文档,步骤为1,2,3: 其实它还自

ASP.NET Core学习之一 入门简介

一.入门简介 在学习之前,要先了解ASP.NET Core是什么?为什么?很多人学习新技术功利心很重,恨不得立马就学会了. 其实,那样做很不好,马马虎虎,联系过程中又花费非常多的时间去解决所遇到的“问题”,是简单的问题,对,就是简单,就是因为觉得简单被忽略的东西,恰恰这才是最重要的. 1.学习资料 首先,介绍下哪里可以获得学习资料 英文官网,最好的文档,英语得过硬 https://docs.microsoft.com/en-us/aspnet/core/ 可惜当年英语就是马马虎虎过来的,所以找了