3

我正在尝试在 ASP.NET Core 中使用JsonPatch来处理模型的部分更新,但是在将 PATCH 发送到 Web API 控制器操作时遇到绑定问题:

我正在使用一个小型库来发出 PATCH 请求:

axios
    .patch('http://localhost:8090/api/characters/1', { bookId: 1, name: 'Bob'})
    .then(function () { /*...*/ })
    .catch(function() { /*...*/ });

这是原始请求:

PATCH http://localhost:8090/api/characters/6 HTTP/1.1
Host: localhost:8090
Connection: keep-alive
Content-Length: 30
Accept: application/json, text/plain, */*
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:3000/library/book/2/character/6
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-AU,en;q=0.8,ru;q=0.6

{"bookId":1,"name":"Bob"}

我的视图模型:

public class UpdateCharacterViewModel
{
    public string Name { get; set; }
}

最后,Web API 操作:

[Route("~/api/[controller]/{characterId}")]
[HttpPatch]
public IActionResult Update(int characterId, [FromBody]UpdateCharacterViewModel viewModel, [FromBody]JsonPatchDocument<UpdateCharacterViewModel> patch)
{
    // viewModel is bound correctly but patch is NULL
    // ...
}

我发现这patch是通过 as NULL,表明绑定存在问题。为了检查请求没有问题,我添加了viewModel并发现它正确绑定 - 填充UpdateCharacterViewModel可用于操作。

我在这里做错了什么?

4

1 回答 1

9

啊,哎呀。看起来请求数据需要采用某种格式,而我错误地认为补丁是基于请求数据中包含或未包含的属性的隐含属性。

以下是请求与 JsonPatchDocument 一起正常工作的示例:

PATCH /api/characters/1
[
    {
      "op": "replace",
      "path": "/name",
      "value": "Bob"
    }
]

值得庆幸的是,有一些库可以轻松创建此补丁数据。JSON-patch似乎是一个不错的选择。您可以通过观察对象的更改来生成补丁数据:

var myobj = { firstName:"Joachim", lastName:"Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
observer = jsonpatch.observe( myobj );
myobj.firstName = "Albert";
myobj.contactDetails.phoneNumbers[0].number = "123";
myobj.contactDetails.phoneNumbers.push({number:"456"});
var patches = jsonpatch.generate(observer);
// patches  == [
//   { op:"replace", path="/firstName", value:"Albert"},
//   { op:"replace", path="/contactDetails/phoneNumbers/0/number", value:"123"},
//   { op:"add", path="/contactDetails/phoneNumbers/1", value:{number:"456"}}];

或者,您可以在两个对象之间运行差异:

var objA = {user: {firstName: "Albert", lastName: "Einstein"}};
var objB = {user: {firstName: "Albert", lastName: "Collins"}};
var diff = jsonpatch.compare(objA, objB));
//diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]

最后,请注意我调试 API 控制器操作的尝试。根据this question的答案,您只能用[FromBody]属性装饰一个参数。后面的所有参数都可以不绑定!

于 2016-08-22T07:26:32.580 回答