您的位置:首页 > 编程语言 > ASP

【ASP.NET Core学习】Web API

aicmilan 2019-12-05 01:08 134 查看 https://www.cnblogs.com/Wilson

 这里介绍在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)
});
}
}
}
View Code

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);
}
}
View Code

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"
},
]
View Code

简单介绍一下,

文件后缀是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;
}
View Code

 

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);
}
View Code

失败的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"
},
]
View Code

 

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"
},
]
View Code  

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

/// <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>
View Code ProducesResponseType 描述返回类型

remarks 会生成请求说明

  • 效果

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

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

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

    标签: