Ronald Ramos
Ronald Ramos

Reputation: 5480

How to implement JsonPatch in .NET Core 3.0 Preview 9 correctly?

I am trying to implement JsonPatch on .NET Core 3.0 Preview 9 web api.

The model:

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

The web api endpoint:

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

The JSON payload:

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

Using PATCH via Postman, I got this error:

{
"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."
    ]
}
}

Here's the complete request/response from Postman

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 Reference:

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

What is wrong with my code?

Thanks.

Upvotes: 7

Views: 6793

Answers (3)

HyperSquid
HyperSquid

Reputation: 21

For those using .NET Core 6.0:

Add the Nuget package: Microsoft.AspNetCore.Mvc.NewtonsoftJson to your project

Then add this using statement to your Program.cs:

using Newtonsoft.Json.Serialization;

Finally add this code to your Program.cs:

builder.Services.AddControllers(options =>
{
    options.ReturnHttpNotAcceptable = true;
}).AddXmlDataContractSerializerFormatters().AddNewtonsoftJson();

Upvotes: -1

fingers10
fingers10

Reputation: 7977

Support for JsonPatch is enabled using the Microsoft.AspNetCore.Mvc.NewtonsoftJson package. To enable this feature, apps must:

  • Install the Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet package.

  • Update the project's Startup.ConfigureServices method to include a call to AddNewtonsoftJson

services
    .AddControllers()
    .AddNewtonsoftJson();

AddNewtonsoftJson is compatible with the MVC service registration methods:

  • AddRazorPages
  • AddControllersWithViews
  • AddControllers

But if you are using asp.net core 3.x, then

AddNewtonsoftJson replaces the System.Text.Json based input and output formatters used for formatting all JSON content. To add support for JsonPatch using Newtonsoft.Json, while leaving the other formatters unchanged, update the project's Startup.ConfigureServices as follows:

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();
}

The preceding code requires a reference to Microsoft.AspNetCore.Mvc.NewtonsoftJson and the following using statements:

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;

A brief explanation and documentation for the above can be found in this link

Upvotes: 12

inliner49er
inliner49er

Reputation: 1450

This answer is for 3.1, but I think it applies to 3.0 as well.... The default json parser in asp.net core 3.x isn't as complete as NewtonsoftJson, so use it until Microsoft implements a feature.

Add this nuget package to your project: Microsoft.AspNetCore.Mvc.NewtonsoftJson

Then add this using statement in startup.cs:

using Newtonsoft.Json.Serialization;

... Then change your ConfigureService() to include the NewtonsoftJson formatter in startup.cs:

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

You may also have to add Accept set to application/json to your requests to prevent them returning XML.

Hope this helps.

Upvotes: 6

Related Questions