原文: JSON Patch With ASP.NET Core

作者:.NET Core Tutorials

译文:如何在ASP.NET Core中使用JSON Patch

地址:https://www.cnblogs.com/lwqlun/p/10433615.html

译者:Lamond Lu

JSON Patch是一种使用API显式更新文档的方法。它本身是一种契约,用于描述如何修改文档(例如:将字段的值替换成另外一个值),而不必同时发送其他未更改的属性值。

一个JSON Patch请求是什么样的?

你可以在以下链接(http://jsonpatch.com/)中找到JSON Patch的官方文档,但是这里我们将进一步研究一下如何在ASP.NET Core中实现JSON Patch。

为了演示JSON Patch, 我创建了以下C#对象类, 后续我将使用JSON Patch请求来操作这个对象类的实例。

public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<string> Friends { get; set; }
}

所有的JSON Patch请求都是遵循一个相似的结构。它有一个固定的“操作”列表。每个操作本身拥有3个属性:

  • "op" - 定义了你要执行何种操作,例如add, replace, test等。
  • "path" - 定义了你要操作对象属性路径。用前面的Person类为例,如果你希望修改FirstName属性,那么你使用的操作路径应该是"/FirstName"。
  • "value" - 在大部分情况下,这个属性表示你希望在操作中使用的值。

现在让我们来看一下每一个的操作如何使用。

Add

Add操作通常意味着你要向对象中添加属性,或者向数组中添加项目。对于前者,在C#中是没有用的,因为C#是强类型语言,所以不能将属性添加到编译时尚未定义的对象上。

所以这里如果想往数组中添加项目,PATCH请求的内容应该如下所示。

{ "op": "add", "path": "/Friends/1", "value": "Mike" }

这将在Friends数组的索引1处插入一个"Mike"值。

或者你还可以使用"-"在数组尾部插入记录。

{ "op": "add", "path": "/Friends/-", "value": "Mike" }

Remove

与Add操作类似,删除操作意味着你希望删除对象中属性,或者从数据中删除某一项。但是因为在C#中你无法移除属性,实际操作时,它会将属性的值变更为default(T)。在某些情况下,如果属性是可空的,则会设置属性值为NULL。但是需要小心,因为当在值类型上使用时,例如int, 则该值实际上会重置为"0"。

如果要在对象上删除某一属性以达到重置的效果,你可以使用一下命令。

{ "op": "remove", "path": "/FirstName"}

当然你也可以使用删除命令删除数组中的某一项。

{ "op": "remove", "path": "/Friends/1" }

这将删除数组索引为1的项目。但是有时候使用索引从数组中删除数据是非常危险的,因为这里没有一个"where"条件来控制删除, 有可能在删除的时候,数据库中对应数组已经发生变化了。实际上有一个JSON Patch操作可以帮助解决这个问题,后面我会描述它。

Replace

Replace操作和它的字面意思完全一样,可以使用它来替换已有值。针对简单属性,你可以使用如下的命令。

{ "op": "replace", "path": "/FirstName", "value": "Jim" }

你同样可以使用它来替换数组中的对象。

{ "op": "replace", "path": "/Friends/1", "value": "Bob" }

你甚至可以用它来替换整个数组。

{ "op": "replace", "path": "/Friends", "value": ["Bob", "Bill"] }

Copy

Copy操作可以将值从一个路径复制到另一个路径。这个值可以是属性,对象,或者数据。在下面的例子中,我们将FirstName属性的值复制到了LastName属性上。这个命令的使用场景不是很多。

{ "op": "copy", "from": "/FirstName", "path" : "/LastName" }

Move

Move操作非常类似于Copy操作,但是正如它的字面意思,"from"字段的值将被移除。如果你看一下ASP.NET Core的JSON Patch的底层代码,你会发现,它实际上它会在"from"路径上执行Remove操作,在"path"路径上执行Add操作。

{ "op": "move", "from": "/FirstName", "path" : "/LastName" }

Test

在当前的ASP.NET Core公开发行版中没有Test操作,但是如果你在Github上查看源代码,你会发现微软已经处理了Test操作。Test操作是一种乐观锁定的方法,或者更简单的说,它会检测数据对象从服务器读取之后,是否发生了更改。

我们以如下操作为例。

[
{ "op": "test", "path": "/FirstName", "value": "Bob" }
{ "op": "replace", "path": "/FirstName", "value": "Jim" }
]

这个操作首先会检查"/FirstName"路径的值是否"Bob", 如果是,就将它改为"Jim"。 如果不是,则什么事情都不会发生。这里你需要注意,在一个Test操作的请求体内可以包含多个Test操作,但是如果其中任何一个Test操作验证失败,所以的变更操作都不会被执行。

为什么要使用JSON Patch?

JSON Patch的一大优势在于它的请求操作体很小,只发送对象的更改内容。 但是在ASP.NET Core中使用JSON Patch还有另一个很大的好处,就是C#是一种强类型语言,无法区分是要将模型的值设置为NULL,还是忽略该属性, 而使用JSON Patch可以解决这个问题。

这里如果没有好的例子,很难解释。 所以想象一下我从API请求一个“Person”对象。 在C#中,模型可能如下所示:


public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

当从API返回Json对象时,它看起来可能像这样。

{
"firstName" : "James",
"lastName" : "Smith"
}

现在在前端,如果不使用JSON Patch, 如果我只想更新FirstName, 我可能在请求中附带一下请求体。

{
"firstName" : "Jim"
}

现在当我在C#中反序列化这个模型时,问题就出现了。不要看下面的代码,想一下此时我们的模型中的属性值是什么?

public class Person
{
public string FirstName { get; set; } //Jim
public string LastName { get; set; } //<Null>
}

因为我们发送LastName属性的值,所以它被反序列化为Null。 但这很简单,我们可以忽略NULL的值,只更新我们实际传递的字段。 但这不一定是正确的,如果该字段实际上可以为空呢? 如果我们发送了以下请求体怎么办?

{
"firstName" : "Jim",
"lastName" : null
}

所以现在我们实际上已经指定我们想要取消该字段。但是因为C#是强类型的,所以我们无法在服务器端进行模型绑定的时候,我们无法确定它是否要将该字段的值设置为NULL。

这似乎是一个奇怪的场景,因为前端可以始终发送完整的数据模型,永远不会省略字段。并且在大多数情况下,前端Web库的模型将始终与API的模型匹配。但有一种情况并非如此,那就是移动应用程序。通常向苹果应用商店提交手机应用,可能需要数周时间才能获得批准。在这个时候,你可能还需要在Web或Android应用程序中使用新模型。在不同平台之间实现同步非常困难,而且通常是不可能。虽然API版本确实对解决这个问题有很长的路要走,但我仍然认为JSON Patch在解决这个问题方面具有很大的实用性。

最后,让我们使用JSON Patch!我们可以使用以下JSON Patch请求更新Person对象

[
{
"op": "replace",
"path": "/FirstName",
"value": "Jim"
}
]

这明确表示我们想要更改名字而不是其他内容。 它准确的告诉我们到底将要发生什么。

在ASP.NET Core项目中启用JSON Patch

在Visual Studio中,我们可以在Package Manage Console中安装官方的Json Patch库(默认创建的ASP.NET Core项目中没有该库)。

Install-Package Microsoft.AspNetCore.JsonPatch

为了演示,我将添加如下的一个控制器类。这里需要注意我们使用的HTTP verb是HttpPatch, 请求参数的类型是JsonPatchDocument。 为了更新对象,我们只需要简单调用ApplyTo方法,并传入了需要更新的对象。

[Route("api/[controller]")]
public class PersonController : Controller
{
private readonly Person _defaultPerson = new Person
{
FirstName = "Jim",
LastName = "Smith"
}; [HttpPatch("update")]
public Person Patch([FromBody]JsonPatchDocument<Person> personPatch)
{
personPatch.ApplyTo(_defaultPerson);
return _defaultPerson;
}
} public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

在以上示例中,我们只是使用了存放在控制器中的简单对象并对其进行了更新,但是在正式的API中,我们需要从数据库中拉取数据对象,更新对象,并重新保存到数据库。

当我们使用如下请求体发送JSON Patch请求时:

[
{"op" : "replace", "path" : "/FirstName", "value" : "Bob"}
]

我们可以得到如下响应内容:

{
"firstName": "Bob",
"lastName": "Smith"
}

真棒! 我们的名字改为Bob! 使用JSON Patch启动和运行真的很简单。

使用Automapper处理JSON Patch请求

针对JSON Patch的使用,最大的问题是,你经常需要从API返回View Model或者DTO, 并生成PATCH请求。但是如果将这些修改请求应用于数据库对象上?大部分情况下,开发人员都挣扎在与此。这里我们可以使用Automapper来帮助完成这个转换的工作。

例如如下代码:


[HttpPatch("update/{id}")]
public Person Patch(int id, [FromBody]JsonPatchDocument<PersonDTO> personPatch)
{
//获取原始Person对象实例
PersonDatabase personDatabase = _personRepository.GetById(id); //将Person对象实例转换为PersonDTO对象实例
PersonDTO personDTO = _mapper.Map<PersonDTO>(personDatabase); //应用Patch修改
personPatch.ApplyTo(personDTO); //将更新后的PersonDTO对象,重新映射到Person对象实例中
_mapper.Map(personDTO, personDatabase); //将更新后的Person对象实例保存到数据库
_personRepository.Update(personDatabase); return personDTO;
}

如何在ASP.NET Core中使用JSON Patch的更多相关文章

  1. 如何在ASP.NET Core中应用Entity Framework

    注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...

  2. 如何在ASP.NET Core中使用Azure Service Bus Queue

    原文:USING AZURE SERVICE BUS QUEUES WITH ASP.NET CORE SERVICES 作者:damienbod 译文:如何在ASP.NET Core中使用Azure ...

  3. 如何在ASP.NET Core中自定义Azure Storage File Provider

    文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...

  4. [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置

    [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...

  5. 如何在 ASP.Net Core 中使用 Serilog

    记录日志的一个作用就是方便对应用程序进行跟踪和排错调查,在实际应用上都是引入 日志框架,但如果你的 日志文件 包含非结构化的数据,那么查询起来将是一个噩梦,所以需要在记录日志的时候采用结构化方式. 将 ...

  6. 如何在ASP.NET Core中实现CORS跨域

    注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...

  7. 如何在ASP.NET Core中实现一个基础的身份认证

    注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ...

  8. [转]如何在ASP.NET Core中实现一个基础的身份认证

    本文转自:http://www.cnblogs.com/onecodeonescript/p/6015512.html 注:本文提到的代码示例下载地址> How to achieve a bas ...

  9. ASP.NET Core中返回 json 数据首字母大小写问题

    ASP.NET Core中返回 json 数据首字母大小写问题 在asp.net core中使用ajax请求动态绑定数据时遇到该问题 后台返回数据字段首字母为定义的大写,返回的数据没有问题 但是在前台 ...

随机推荐

  1. Java基本类型和引用类型

      8种基本类型 一.4种整型     byte      1字节           -128--127     short     2 字节         -32,768 -- 32,767   ...

  2. 在C++遇到有些关键字或者函数被弃用的情况

    随着每一次C++的不断更新,可能都会有些函数或者关键字会被弃用,或者换成了其他的名字,这在编写代码的时候经常会碰到,碰到这种情况,可以在代码的第一行写上忽略此错误的句子,一般为: #pragma  w ...

  3. mysql保存不了4字节的问题(也就是表情)

    这个问题   https://blog.csdn.net/ppwangGS/article/details/62044887 有详细的解决办法 这里我就是记录一下我遇到的问题 这种问题一般是往数据库 ...

  4. cocoapods安装及使用其中 添加新源: gem sources -a https://ruby.taobao.org/

    一.概要 iOS开发时,项目中会引用许多第三方库,CocoaPods(https://github.com/CocoaPods/CocoaPods)可以用来方便的统一管理这些第三方库. 二.安装 由于 ...

  5. js模块化 javascript 模块化 闭包写法 闭包模块化写法

    var main = main || {}; ; (function (main) { 'use strict'; //私有变量 var _s1 = 'Hello '; var _s2 = 'Worl ...

  6. 理解线程池到走进dubbo源码

    引言 合理利用线程池能够带来三个好处. ​ 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. ​ 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. ...

  7. 5.2基于JWT的令牌生成和定制「深入浅出ASP.NET Core系列」

    希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,码字辛苦,如果你吃了蛋觉得味道不错,希望点个赞,谢谢关注. Token生成 我们知道一旦我们给API添加[Authorize] ...

  8. nginx漏洞分析与升级修复

    一 .此次漏洞分析 1 nginx HTTP/2漏洞 [nginx-announce] nginx安全公告(CVE-2018-16843,CVE-2018-16844)在nginx HTTP / 2实 ...

  9. 如何通过免费开源ERP Odoo建立你的团队, 销售过程和目标

    这种快速的一步一步的指南将引导您完成Odoo CRM, 帮助您轻松处理您的销售渠道, 时刻从线索到客户管理您的销售渠道. 配置 从 Odoo初始化后,生成你的数据库, 选择CRM 作为第一个app安装 ...

  10. 初始scrapy,简单项目创建和CSS选择器,xpath选择器(1)

    一 安装 #Linux: pip3 install scrapy #Windows: a. pip3 install wheel b. 下载twisted http://www.lfd.uci.edu ...