Как правильно реализовать JsonPatch в .NET Core 3.0 Preview 9?

Я пытаюсь реализовать JsonPatch на веб-API .NET Core 3.0 Preview 9.

Модель:

public class TestPatch
{
    public string TestPath { get; set; }
}

Конечная точка веб-API:

[HttpPatch()]
public async Task<IActionResult> Update([FromBody] JsonPatchDocument<TestPatch> patch)
{
   ...........
   return Ok();
}

Полезная нагрузка JSON:

[
    {
        "op" : "replace",
        "path" : "/testPath",
        "value" : "new value"
    }
]

Используя PATCH через Postman, я получил эту ошибку:

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|492c592-4f7de4d16a32b942.",
"errors": {
    "$": [
        "The JSON value could not be converted to Microsoft.AspNetCore.JsonPatch.JsonPatchDocument`1[Test.Models.TestPatch]. Path: $ | LineNumber: 0 | BytePositionInLine: 1."
    ]
}
}

Вот полный запрос / ответ от почтальона

PATCH /api/helptemplates HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.16.3
Accept: */*
Cache-Control: no-cache
Postman-Token: a41813ea-14db-4664-98fb-ee30511707bc
Host: localhost:5002
Accept-Encoding: gzip, deflate
Content-Length: 77
Connection: keep-alive
[
{
"op" : "replace",
"path" : "/testPath",
"value" : "new value"
}
]
HTTP/1.1 400 Bad Request
Date: Thu, 12 Sep 2019 21:13:08 GMT
Content-Type: application/problem+json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"|492c593-4f7de4d16a32b942.","errors":{"$":["The JSON value could not be converted to Microsoft.AspNetCore.JsonPatch.JsonPatchDocument`1[Test.Models.TestPatch]. Path: $ | LineNumber: 0 | BytePositionInLine: 1."]}}

Ссылка на JsonPatch:

<PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="3.0.0-preview9.19424.4" />

Что не так с моим кодом?

Спасибо.


person Ronald Ramos    schedule 12.09.2019    source источник
comment
Разместил проблему на странице github.com/aspnet/AspNetCore/issues/13938, и это было решается с помощью Microsoft.AspNetCore.Mvc.NewtonsoftJson.   -  person Ronald Ramos    schedule 13.09.2019


Ответы (2)


Поддержка JsonPatch включается с помощью пакета Microsoft.AspNetCore.Mvc.NewtonsoftJson. Чтобы включить эту функцию, приложения должны:

  • Установите пакет Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet.

  • Обновите метод Startup.ConfigureServices проекта, чтобы включить вызов AddNewtonsoftJson

services
    .AddControllers()
    .AddNewtonsoftJson();

AddNewtonsoftJson совместим с методами регистрации службы MVC:

  • AddRazorPages
  • AddControllersWithViews
  • AddControllers

Но если вы используете asp.net core 3.x, тогда

AddNewtonsoftJson заменяет основанные на System.Text.Json средства форматирования ввода и вывода, используемые для форматирования всего содержимого JSON. Чтобы добавить поддержку JsonPatch с помощью Newtonsoft.Json, оставив другие средства форматирования без изменений, обновите Startup.ConfigureServices проекта следующим образом:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(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;

Краткое объяснение и документацию по вышеизложенному можно найти в этом ссылка

person fingers10    schedule 15.01.2020
comment
Это решение работает, но у меня небольшая проблема. У меня OutputFormatters установлен XmlDataContractSerializerOutputFormatter для поддержки ответов XML. После изменения кода все запросы должны явно указывать заголовок Accept с помощью application / json. В противном случае по умолчанию возвращается XML. Как установить Json как формат вывода по умолчанию? - person SurenSaluka; 06.12.2020
comment
services.AddMvc (options = ›options.EnableEndpointRouting = false) .AddMvcOptions (o =› {o.OutputFormatters.Add (new XmlDataContractSerializerOutputFormatter ()); o.InputFormatters.Insert (0, GetJsonPatch); ); - person SurenSaluka; 06.12.2020
comment
Это из-за порядка вашей конфигурации. Вам нужно добавить services.AddMvc().AddNewtonsodtJson().AddXmlDataContractSerializerFormatters. Обратитесь к моему репозиторию EnterpriseArchitecture. Вам нужно поменять местами порядок регистрации средств форматирования вывода. В Asp.Net Core 3.1 вы можете просто добавить AddXmlDataContractSerializerFormatters. Удалите XmlDataContractSerializerOutputFormatter из AddMvcOptions - person fingers10; 06.12.2020
comment
Большое тебе спасибо. Извините за поздний голос :) - person SurenSaluka; 29.12.2020
comment
Примечание: на данный момент документация не завершена. Если вы используете System.Text.Json со своим API, но NewtonSoft.Json для документов JSON PATCH, клиент должен отправить Content-Type application/json-patch+json вместо application/json, иначе это не сработает. - person Jérôme MEVEL; 30.04.2021

Этот ответ относится к версии 3.1, но я думаю, что он применим и к версии 3.0 .... Парсер json по умолчанию в asp.net core 3.x не так совершенен, как NewtonsoftJson, поэтому используйте его, пока Microsoft не реализует функцию.

Добавьте этот пакет nuget в свой проект: Microsoft.AspNetCore.Mvc.NewtonsoftJson

Затем добавьте этот оператор using в startup.cs:

using Newtonsoft.Json.Serialization;

... Затем измените свой ConfigureService (), чтобы включить средство форматирования NewtonsoftJson в startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(setupAction =>
    setupAction.ReturnHttpNotAcceptable = true
   ).AddXmlDataContractSerializerFormatters().AddNewtonsoftJson(setupAction =>
   setupAction.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());
   //...
}

Возможно, вам также придется добавить набор Accept для application / json в свои запросы, чтобы они не возвращали XML.

Надеюсь это поможет.

person inliner49er    schedule 08.01.2020