在ASP.NET Core WebAPI

时间:2017-09-14 03:29:05

标签: c# asp.net-mvc asp.net-web-api asp.net-core asp.net-core-webapi

我有兴趣在ASP.NET Core WebAPI中添加对部分更新的支持,我只更新调用者提供的资源上的属性,保留排除的属性。

对于上下文,假设我有一个可以描述如下的资源:

GET /users/1
{
    title: "Mister",
    firstName: "Frederick",
    middleName: "McFeely",
    lastName: "Rodgers"
}

如果我想允许消费者将firstName属性中存储的值从“Frederick”单独更改为“Fred”,我应该能够公开支持PATCH的{​​{1}}端点{3}} Content-Type,如下:

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并传递给我的控制器之前提取哪些属性'已在JSON对象上定义了键。我不能假设值null表示属性被排除,因为调用者可以显式地将可选属性设置为null。

修改

我知道JSON Merge Patch库。遗憾的是,这需要调用者使用“[更改说明]”来定义PATCH,如Microsoft.AspNetCore.JsonPatch中所述,我发现它不直观且冗长。我指的是RFC 5789中定义的“JSON Merge Patch”。

5 个答案:

答案 0 :(得分:3)

我找到了一个有效的库:https://github.com/Morcatko/Morcatko.AspNetCore.JsonMergePatch

[HttpPatch]
[Consumes(JsonMergePatchDocument.ContentType)]
public void Patch([FromBody] JsonMergePatchDocument<Model> patch)
{
    ...
    patch.ApplyTo(backendModel);
    ...
}

或者使用patch.JsonPatchDocument.Operations手动浏览补丁请求字段。

答案 1 :(得分:1)

看来,对于合并补丁,您将不得不等待odata支持。

目前处于测试阶段并且支持与Delta&lt;&gt;的合并语义。类。

https://www.nuget.org/packages/Microsoft.AspNetCore.OData/

答案 2 :(得分: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));
}

希望这有助于搜索此主题并寻找无需外部软件包的简单解决方案的人。

答案 3 :(得分:-2)

要做补丁,你必须定义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字段更新为&#39; boo&#39;在用户模型中。

答案 4 :(得分:-2)