在 ASP.NET Core WebAPI 中实现 JSON 合并补丁
Posted
技术标签:
【中文标题】在 ASP.NET Core WebAPI 中实现 JSON 合并补丁【英文标题】:Implementing JSON Merge Patch in ASP.NET Core WebAPI 【发布时间】:2018-02-22 21:42:09 【问题描述】:我有兴趣在我的 ASP.NET Core WebAPI 中添加对部分更新的支持,我只更新调用者提供的资源的属性,而排除的属性保持不变。
对于上下文,假设我有一个可以描述如下的资源:
GET /users/1
title: "Mister",
firstName: "Frederick",
middleName: "McFeely",
lastName: "Rodgers"
如果我想允许消费者将存储在firstName
属性中的值从“Frederick”单独更改为“Fred”,我应该能够公开一个支持JSON Merge Patch@987654328 的PATCH
端点@,就像这样:
PATCH /users/1
Content-Type: application/merge-patch+json
firstName: "Fred"
但是,我认为没有简单的方法可以知道 firstName
是唯一正在更新的属性。例如,如果我要创建一个接受PATCH
动词的控制器,它可以像这样搭建:
[Route("users")]
public class UsersController : Controller
[HttpPatch("userId:int")]
public User Patch([FromRoute] int userId, [FromBody] User user)
// How do I know which properties were set on User at this point?
public class User
public String Title get; set;
public String FirstName get; set;
public String MiddleName get; set;
public String LastName get; set;
但我不知道如何提取在 JSON 对象上定义了哪些属性的键,然后再将其作为User
水合并传递给我的控制器。我不能假设 null
的值意味着一个属性被排除在外,因为调用者可能明确地将一个可选属性设置为 null。
编辑
我知道Microsoft.AspNetCore.JsonPatch 库。不幸的是,这期望调用者使用“[description of changes]”来定义PATCH
,如RFC 5789 中所述,我觉得这既不直观又冗长。我指的是RFC 7396中定义的“JSON Merge Patch”。
【问题讨论】:
【参考方案1】:对于简单类型,我找到了一个非常简单的解决方案,使用 JObjects 的Newtonsoft.Json merge:
public static T Patched<T>(T source, JObject patch) where T : class
var sourceObject = JObject.FromObject(source);
sourceObject.Merge(patch, new JsonMergeSettings() MergeArrayHandling = MergeArrayHandling.Union);
return sourceObject.ToObject<T>();
public static T Patched<T>(T source, string patchCode) where T : class
return Patched<T>(source, JObject.Parse(patchCode));
希望这可以帮助搜索此主题并寻找没有外部包的简单解决方案的人。
【讨论】:
【参考方案2】:我找到了一个有效的库:https://github.com/Morcatko/Morcatko.AspNetCore.JsonMergePatch
[HttpPatch]
[Consumes(JsonMergePatchDocument.ContentType)]
public void Patch([FromBody] JsonMergePatchDocument<Model> patch)
...
patch.ApplyTo(backendModel);
...
或使用patch.JsonPatchDocument.Operations
手动浏览补丁请求字段。
【讨论】:
【参考方案3】:看起来,对于合并补丁,您将不得不等待 odata 支持。
目前处于测试阶段,支持与 Delta 类的合并语义。
https://www.nuget.org/packages/Microsoft.AspNetCore.OData/
【讨论】:
很好,这看起来很有希望。我会在它发布时回过头来讨论它。 在 7.0.0 中反序列化实体时,实体 ID 和集合存在一些问题:(【参考方案4】:您可能正在寻找的是 ASP.Net Core JsonPatchDocument
https://github.com/aspnet/JsonPatch
https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.aspnetcore.jsonpatch
【讨论】:
【参考方案5】:要打补丁,你必须定义 PatchDocument。
更多信息你可以找到PatchDocument
方法示例。
[HttpPatch("userId:int")]
public IActionResult UserPatch(int userId, [FromBody] JsonPatchDocument<User> patchDocument)
var user = new User();
// Because it comes from url.
user.Id = userId;
patchDocument.ApplyTo(user);
// Here you call context or repository to save.
文档示例。
[
"op": "replace", "path": "/firstName", "value": "boo" ,
]
这会将用户模型中的 firstName 字段更新为“boo”。
【讨论】:
您好,感谢您的回答。不幸的是,您将the original idea of PATCH 与我正在寻找的东西混淆了:JSON Merge PATCH。它们使用相同的动词,但后者是 RFC 中定义的特定内容类型。以上是关于在 ASP.NET Core WebAPI 中实现 JSON 合并补丁的主要内容,如果未能解决你的问题,请参考以下文章
在 ASP.NET Core 2.1 Web API 中实现分页
使用 Microsoft System.IdentityModel.Tokens.Jwt 在 Asp.net WebApi 中实现 JWT 身份验证
在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务