JsonPatch в веб-API ASP.NET Core
В этой статье объясняется, как обрабатывать JSзапросы на исправление ON в веб-API ASP.NET Core.
Установка пакета
JSПоддержка исправлений ON в веб-API ASP.NET Core основана Newtonsoft.Json
на пакете Microsoft.AspNetCore.Mvc.NewtonsoftJson
NuGet. Чтобы включить JSподдержку исправлений ON, выполните приведенные действия.
Установите пакет NuGet
Microsoft.AspNetCore.Mvc.NewtonsoftJson
.Вызовите процедуру AddNewtonsoftJson. Например:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
AddNewtonsoftJson
заменяет входные и выходные средства форматирования на основе по умолчанию System.Text.Json
, используемые для форматирования всегоJSсодержимого ON. Этот метод расширения совместим со следующими методами регистрации службы MVC:
JsonPatch требует установки заголовка Content-Type
application/json-patch+json
в значение .
Добавление поддержки on JSPatch при использовании System.Text.Json
Модуль форматирования входных данных на основе не поддерживает JSисправление System.Text.Json
ON. Чтобы добавить поддержку on JSPatch с помощью Newtonsoft.Json
, оставляя другие входные и выходные форматировщики без изменений:
Установите пакет NuGet
Microsoft.AspNetCore.Mvc.NewtonsoftJson
.Обновление
Program.cs
:using JsonPatchSample; using Microsoft.AspNetCore.Mvc.Formatters; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(options => { options.InputFormatters.Insert(0, MyJPIF.GetJsonPatchInputFormatter()); }); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.Options; namespace JsonPatchSample; public static class MyJPIF { public static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter() { var builder = new ServiceCollection() .AddLogging() .AddMvc() .AddNewtonsoftJson() .Services.BuildServiceProvider(); return builder .GetRequiredService<IOptions<MvcOptions>>() .Value .InputFormatters .OfType<NewtonsoftJsonPatchInputFormatter>() .First(); } }
Предыдущий код создает экземпляр NewtonsoftJsonPatchInputFormatter и вставляет его в качестве первой записи в коллекцию MvcOptions.InputFormatters . Этот порядок регистрации гарантирует, что:
NewtonsoftJsonPatchInputFormatter
обрабатывает JSзапросы на исправление ON.- Существующие
System.Text.Json
входные и форматирующие модули обрабатывают все остальные JSзапросы и ответы ON.
Используйте Newtonsoft.Json.JsonConvert.SerializeObject
метод для сериализации JsonPatchDocument.
Метод HTTP-запроса PATCH
Методы PUT и PATCH используются для обновления существующего ресурса. Различие между ними заключается в том, что PUT заменяет весь ресурс, а PATCH указывает только изменения.
JSИсправление ON
JS Исправление ON — это формат для указания обновлений, применяемых к ресурсу. Документ JSON Patch содержит массив операций. Каждая операция определяет определенный тип изменения. Примеры таких изменений включают добавление элемента массива или замена значения свойства.
Например, следующие JSдокументы ON представляют ресурс, JSдокумент ON Patch для ресурса и результат применения операций исправления.
Пример ресурса
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
JSПример исправления ON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
В приведенном выше коде JSON:
- свойство
op
указывает тип операции; - свойство
path
указывает обновляемый элемент; - свойство
value
предоставляет новое значение.
Ресурс после обновления
Ниже приведен ресурс после применения предыдущего JSдокумента ON Patch:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Изменения, внесенные применением документа ON Patch к ресурсу JS, являются атомарными. Если любая операция в списке завершается ошибкой, операция в списке не применяется.
Синтаксис Path
Свойство Path в объекте операции содержит косые черты между уровнями. Например, "/address/zipCode"
.
Для указания элементов массива используются числовые индексы, начиная с нуля. Первый элемент массива addresses
будет обозначаться как /addresses/0
. В add
конце массива используйте дефис (-
) вместо номера индекса: /addresses/-
Operations
В следующей таблице показаны поддерживаемые операции, определенные в JSспецификации ON Patch:
Операция | Примечания. |
---|---|
add |
Добавляет свойство или элемент массива. Для существующего свойства устанавливает значение. |
remove |
Удаляет свойство или элемент массива. |
replace |
Действует так же, как remove с последующим add в том же расположении. |
move |
Действует так же, как remove из источника с последующим add , в котором указаны место назначения и значение из источника. |
copy |
Действует так же, как add , в котором указаны место назначения и значение из источника. |
test |
Возвращает успешный код состояния, если значение path совпадает с предоставленным value . |
JSИсправление ON в ASP.NET Core
Реализация on Patch ASP.NET core JSпредоставляется в пакете NuGet Microsoft.AspNetCore.JsonPatch .
Код метода действия
В контроллере API метод действия для JSON Patch:
- помечен атрибутом
HttpPatch
; - принимает JsonPatchDocument<TModel> обычно с указанием
[FromBody]
; - вызывает ApplyTo(Object) для целевого документа, чтобы применить изменения.
Ниже приведен пример:
[HttpPatch]
public IActionResult JsonPatchWithModelState(
[FromBody] JsonPatchDocument<Customer> patchDoc)
{
if (patchDoc != null)
{
var customer = CreateCustomer();
patchDoc.ApplyTo(customer, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return new ObjectResult(customer);
}
else
{
return BadRequest(ModelState);
}
}
Этот код из примера приложения работает со следующей Customer
моделью:
namespace JsonPatchSample.Models;
public class Customer
{
public string? CustomerName { get; set; }
public List<Order>? Orders { get; set; }
}
namespace JsonPatchSample.Models;
public class Order
{
public string OrderName { get; set; }
public string OrderType { get; set; }
}
Этот пример метода действия:
- Создает документ
Customer
. - применяет изменения;
- возвращает результат в тексте ответа.
В реальном приложении код будет извлекать данные из хранилища, например из базы данных, и обновлять эту базу данных после применения исправлений.
Состояние модели
Указанный выше пример метода действия вызывает перегрузку ApplyTo
, которая принимает состояние модели в качестве одного из параметров. В этом случае вы получаете в ответах сообщения об ошибках. В следующем примере показан текст ответа с кодом 400 "Неверный запрос" для операции test
:
{
"Customer": [
"The current value 'John' at path 'customerName' != test value 'Nancy'."
]
}
Динамические объекты
В следующем примере метода действия показано, как применить исправление к динамическому объекту:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Операция добавления
- Если
path
указывает на элемент массива, новый элемент вставляется перед тем, который указан в параметреpath
. - Если
path
указывает на свойство, задается значение свойства. - Если
path
указывает на несуществующее расположение:- Если обновляемый ресурс является динамическим объектом, добавляется свойство.
- Если обновляемый ресурс является статическим объектом, запрос завершается ошибкой.
Следующий пример документа с исправлениями устанавливает значение CustomerName
и добавляет объект Order
в конец массива Orders
.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Операция удаления
- Если
path
указывает на элемент массива, элемент удаляется. - Если
path
указывает на свойство:- Если обновляемый ресурс является динамическим объектом, свойство удаляется.
- Если ресурс для исправления является статическим объектом:
- Если свойство может принимать значения NULL, ему присваивается значение NULL.
- Если свойство не может принимать значения NULL, ему присваивается значение
default<T>
.
В следующем примере наборов документов исправлений CustomerName
задано значение NULL и удаляется Orders[0]
:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Операция замены
Эта операция функционально идентична операции remove
с последующей add
.
Следующий пример документа исправления задает значение CustomerName
и заменяет Orders[0]
новый Order
объект:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Операция перемещения
- Если
path
указывает на элемент массива, элементfrom
копируется в расположение элементаpath
, а затем выполняется операцияremove
для элементаfrom
. - Если
path
указывает на свойство, значение свойстваfrom
копируется в свойствоpath
, а затем выполняется операцияremove
для свойстваfrom
. - Если
path
указывает на несуществующее свойство:- Если обновляемый ресурс является статическим объектом, запрос завершается ошибкой.
- Если исправляемый ресурс является динамическим объектом, значение
from
копируется в местоположение, указанное параметромpath
, а затем выполняется операцияremove
для свойстваfrom
.
Следующий пример документа исправления выполняет следующие действия:
- копирует значение
Orders[0].OrderName
вCustomerName
; - присваивает
Orders[0].OrderName
значение NULL; - перемещает
Orders[1]
в расположение передOrders[0]
.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Операция копирования
Эта операция функционально аналогична операции move
без последнего шага remove
.
Следующий пример документа исправления выполняет следующие действия:
- копирует значение
Orders[0].OrderName
вCustomerName
; - вставляет копию
Orders[1]
передOrders[0]
.
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Операция тестирования
Если значение в расположении, которое задано параметром path
, отличается от предоставленного в value
значения, запрос завершится ошибкой. В этом случае сбой распространяется на весь запрос PATCH, даже если все остальные операции в документе с исправлениями могли быть выполнены успешно.
Операция test
традиционно используется для предотвращения обновлений при возможных конфликтах параллелизма.
Следующий пример документа с исправлениями не изменяет прежнее значение CustomerName
(John), так как тест завершается ошибкой:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Получение кода
Просмотреть или скачать образец кода. (Инструкция по скачиванию.)
Чтобы проверить этот пример, запустите приложение и отправьте HTTP-запросы со следующими параметрами:
- URL-адрес:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate
- Метод HTTP:
PATCH
- заголовок:
Content-Type: application/json-patch+json
; - Текст: скопируйте и вставьте один из JSпримеров документов исправлений JSON из папки проекта ON .
Дополнительные ресурсы
- Спецификация IETF RFC 5789 для метода PATCH
- Спецификация IETF RFC 6902 JSON Patch
- Указатель IETF RFC 6901 JSON
- JSДокументация по исправлению ON. Содержит ссылки на ресурсы для создания JSдокументов с исправлением ON.
- исходный код ASP.NET Core JSON Patch
В этой статье объясняется, как обрабатывать JSзапросы на исправление ON в веб-API ASP.NET Core.
Установка пакета
Чтобы включить JSподдержку исправлений ON в приложении, выполните следующие действия.
Установите пакет NuGet
Microsoft.AspNetCore.Mvc.NewtonsoftJson
.Обновите метод проекта
Startup.ConfigureServices
для вызова AddNewtonsoftJson. Например:services .AddControllersWithViews() .AddNewtonsoftJson();
AddNewtonsoftJson
совместим с методами регистрации службы MVC:
JSON Patch, AddNewtonsoftJson и System.Text.Json
AddNewtonsoftJson
System.Text.Json
заменяет средства форматирования входных и выходных данных на основе, используемые для форматирования всегоJSсодержимого ON. Чтобы добавить поддержку on JSPatch с помощью Newtonsoft.Json
, оставляя другие форматировщики без изменений, обновите метод проекта Startup.ConfigureServices
следующим образом:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.InputFormatters.Insert(0, GetJsonPatchInputFormatter());
});
}
private static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter()
{
var builder = new ServiceCollection()
.AddLogging()
.AddMvc()
.AddNewtonsoftJson()
.Services.BuildServiceProvider();
return builder
.GetRequiredService<IOptions<MvcOptions>>()
.Value
.InputFormatters
.OfType<NewtonsoftJsonPatchInputFormatter>()
.First();
}
Для предыдущего кода требуется Microsoft.AspNetCore.Mvc.NewtonsoftJson
пакет и следующие using
инструкции:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System.Linq;
Используйте Newtonsoft.Json.JsonConvert.SerializeObject
метод для сериализации JsonPatchDocument.
Метод HTTP-запроса PATCH
Методы PUT и PATCH используются для обновления существующего ресурса. Различие между ними заключается в том, что PUT заменяет весь ресурс, а PATCH указывает только изменения.
JSИсправление ON
JS Исправление ON — это формат для указания обновлений, применяемых к ресурсу. Документ JSON Patch содержит массив операций. Каждая операция определяет определенный тип изменения. Примеры таких изменений включают добавление элемента массива или замена значения свойства.
Например, следующие JSдокументы ON представляют ресурс, JSдокумент ON Patch для ресурса и результат применения операций исправления.
Пример ресурса
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
JSПример исправления ON
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
В приведенном выше коде JSON:
- свойство
op
указывает тип операции; - свойство
path
указывает обновляемый элемент; - свойство
value
предоставляет новое значение.
Ресурс после обновления
Ниже приведен ресурс после применения предыдущего JSдокумента ON Patch:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Изменения, внесенные применением документа ON Patch к ресурсу JS, являются атомарными. Если любая операция в списке завершается ошибкой, операция в списке не применяется.
Синтаксис Path
Свойство Path в объекте операции содержит косые черты между уровнями. Например, "/address/zipCode"
.
Для указания элементов массива используются числовые индексы, начиная с нуля. Первый элемент массива addresses
будет обозначаться как /addresses/0
. В add
конце массива используйте дефис (-
) вместо номера индекса: /addresses/-
Operations
В следующей таблице показаны поддерживаемые операции, определенные в JSспецификации ON Patch:
Операция | Примечания. |
---|---|
add |
Добавляет свойство или элемент массива. Для существующего свойства устанавливает значение. |
remove |
Удаляет свойство или элемент массива. |
replace |
Действует так же, как remove с последующим add в том же расположении. |
move |
Действует так же, как remove из источника с последующим add , в котором указаны место назначения и значение из источника. |
copy |
Действует так же, как add , в котором указаны место назначения и значение из источника. |
test |
Возвращает успешный код состояния, если значение path совпадает с предоставленным value . |
JSИсправление ON в ASP.NET Core
Реализация on Patch ASP.NET core JSпредоставляется в пакете NuGet Microsoft.AspNetCore.JsonPatch .
Код метода действия
В контроллере API метод действия для JSON Patch:
- помечен атрибутом
HttpPatch
; - принимает
JsonPatchDocument<T>
обычно с указанием[FromBody]
; - вызывает
ApplyTo
для целевого документа, чтобы применить изменения.
Ниже приведен пример:
[HttpPatch]
public IActionResult JsonPatchWithModelState(
[FromBody] JsonPatchDocument<Customer> patchDoc)
{
if (patchDoc != null)
{
var customer = CreateCustomer();
patchDoc.ApplyTo(customer, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return new ObjectResult(customer);
}
else
{
return BadRequest(ModelState);
}
}
Этот код из примера приложения работает со следующей Customer
моделью:
using System.Collections.Generic;
namespace JsonPatchSample.Models
{
public class Customer
{
public string CustomerName { get; set; }
public List<Order> Orders { get; set; }
}
}
namespace JsonPatchSample.Models
{
public class Order
{
public string OrderName { get; set; }
public string OrderType { get; set; }
}
}
Этот пример метода действия:
- Создает документ
Customer
. - применяет изменения;
- возвращает результат в тексте ответа.
В реальном приложении код будет извлекать данные из хранилища, например из базы данных, и обновлять эту базу данных после применения исправлений.
Состояние модели
Указанный выше пример метода действия вызывает перегрузку ApplyTo
, которая принимает состояние модели в качестве одного из параметров. В этом случае вы получаете в ответах сообщения об ошибках. В следующем примере показан текст ответа с кодом 400 "Неверный запрос" для операции test
:
{
"Customer": [
"The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
]
}
Динамические объекты
В следующем примере метода действия показано, как применить исправление к динамическому объекту:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Операция добавления
- Если
path
указывает на элемент массива, новый элемент вставляется перед тем, который указан в параметреpath
. - Если
path
указывает на свойство, задается значение свойства. - Если
path
указывает на несуществующее расположение:- Если обновляемый ресурс является динамическим объектом, добавляется свойство.
- Если обновляемый ресурс является статическим объектом, запрос завершается ошибкой.
Следующий пример документа с исправлениями устанавливает значение CustomerName
и добавляет объект Order
в конец массива Orders
.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Операция удаления
- Если
path
указывает на элемент массива, элемент удаляется. - Если
path
указывает на свойство:- Если обновляемый ресурс является динамическим объектом, свойство удаляется.
- Если ресурс для исправления является статическим объектом:
- Если свойство может принимать значения NULL, ему присваивается значение NULL.
- Если свойство не может принимать значения NULL, ему присваивается значение
default<T>
.
В следующем примере наборов документов исправлений CustomerName
задано значение NULL и удаляется Orders[0]
:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Операция замены
Эта операция функционально идентична операции remove
с последующей add
.
Следующий пример документа исправления задает значение CustomerName
и заменяет Orders[0]
новый Order
объект:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Операция перемещения
- Если
path
указывает на элемент массива, элементfrom
копируется в расположение элементаpath
, а затем выполняется операцияremove
для элементаfrom
. - Если
path
указывает на свойство, значение свойстваfrom
копируется в свойствоpath
, а затем выполняется операцияremove
для свойстваfrom
. - Если
path
указывает на несуществующее свойство:- Если обновляемый ресурс является статическим объектом, запрос завершается ошибкой.
- Если исправляемый ресурс является динамическим объектом, значение
from
копируется в местоположение, указанное параметромpath
, а затем выполняется операцияremove
для свойстваfrom
.
Следующий пример документа исправления выполняет следующие действия:
- копирует значение
Orders[0].OrderName
вCustomerName
; - присваивает
Orders[0].OrderName
значение NULL; - перемещает
Orders[1]
в расположение передOrders[0]
.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Операция копирования
Эта операция функционально аналогична операции move
без последнего шага remove
.
Следующий пример документа исправления выполняет следующие действия:
- копирует значение
Orders[0].OrderName
вCustomerName
; - вставляет копию
Orders[1]
передOrders[0]
.
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Операция тестирования
Если значение в расположении, которое задано параметром path
, отличается от предоставленного в value
значения, запрос завершится ошибкой. В этом случае сбой распространяется на весь запрос PATCH, даже если все остальные операции в документе с исправлениями могли быть выполнены успешно.
Операция test
традиционно используется для предотвращения обновлений при возможных конфликтах параллелизма.
Следующий пример документа с исправлениями не изменяет прежнее значение CustomerName
(John), так как тест завершается ошибкой:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Получение кода
Просмотреть или скачать образец кода. (Инструкция по скачиванию.)
Чтобы проверить этот пример, запустите приложение и отправьте HTTP-запросы со следующими параметрами:
- URL-адрес:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate
- Метод HTTP:
PATCH
- заголовок:
Content-Type: application/json-patch+json
; - Текст: скопируйте и вставьте один из JSпримеров документов исправлений JSON из папки проекта ON .
Дополнительные ресурсы
- Спецификация IETF RFC 5789 для метода PATCH
- Спецификация IETF RFC 6902 JSON Patch
- Спецификация формата пути исправления IETF RFC 6901 JSON
- JSДокументация по исправлению ON. Содержит ссылки на ресурсы для создания JSдокументов с исправлением ON.
- исходный код ASP.NET Core JSON Patch
ASP.NET Core
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по