JsonPatchDocument неправильно связывается

Я пытаюсь использовать JsonPatch в ASP.NET Core для обработки частичных обновлений модели, но у меня есть привязка проблемы, когда PATCH отправляется в действие контроллера веб-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; }
}

И, наконец, действие веб-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 отображается как NULL, что указывает на проблему с привязкой. Чтобы убедиться, что с запросом не возникло проблем, я добавил viewModel и обнаружил, что он правильно связывается — для действия доступен заполненный UpdateCharacterViewModel.

Что я здесь делаю неправильно?


person ajbeaven    schedule 22.08.2016    source источник


Ответы (1)


Ах, упс. Похоже, что данные запроса должны быть в определенном формате, тогда как я ошибочно подумал, что патч был неявным на основе свойств, которые были или не были включены в данные запроса.

Вот пример того, как должен выглядеть запрос для правильной работы с 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"}}];

Или, в качестве альтернативы, вы можете запустить diff между двумя объектами:

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. Согласно ответу на этот вопрос, вы можете украсить только один параметр атрибутом [FromBody]. Все последующие параметры не могут быть привязаны!

person ajbeaven    schedule 22.08.2016
comment
Мне потребовалась бы вечность, чтобы понять, что мне нужно, чтобы операции исправления были в массиве. Спасибо! - person James Bruckner; 04.01.2017