JsonPatchDocument没有正确绑定

时间:2016-08-22 07:18:56

标签: asp.net-core axios json-patch

我正在尝试在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"}

我的ViewModel:

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
    // ...
}

我发现patchNULL的形式出现,表明绑定存在问题。要检查请求是否存在问题,我添加了viewModel并发现它正确绑定 - 操作可以使用已填充的UpdateCharacterViewModel

我在这里做错了什么?

1 个答案:

答案 0 :(得分:5)

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

以下是使用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控制器操作的尝试。根据{{​​3}}的答案,您只能使用[FromBody]属性修饰一个参数。所有后续参数可能不受约束!