JsonPatchDocument没有正确绑定

ajb*_*ven 2 json-patch asp.net-core axios

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

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

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

这是原始请求:

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"}
Run Code Online (Sandbox Code Playgroud)

我的ViewModel:

public class UpdateCharacterViewModel
{
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

最后,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
    // ...
}
Run Code Online (Sandbox Code Playgroud)

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

我在这做错了什么?

ajb*_*ven 7

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

以下是使用JsonPatchDocument正常工作的请求的示例:

PATCH /api/characters/1
[
    {
      "op": "replace",
      "path": "/name",
      "value": "Bob"
    }
]
Run Code Online (Sandbox Code Playgroud)

值得庆幸的是,有一些库可以轻松创建这个补丁数据.JSON补丁似乎是一个很好的补丁.您可以通过观察对象的更改来生成补丁数据:

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"}}];
Run Code Online (Sandbox Code Playgroud)

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

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"}]
Run Code Online (Sandbox Code Playgroud)

最后,要小心我调试API控制器操作的尝试.根据这个问题的答案,你只能用[FromBody]属性装饰一个参数.所有后续参数可能不受约束!

  • 这将让我永远意识到我需要将补丁操作放在一个数组中.谢谢! (5认同)