Why model binding to JObject from a request doesn’t work anymore in ASP.NET Core 3.1 and what’s the alternative ?
Introduction
Json.Net (NewtonSoft) has been for a long time the most used JSON serializer in .NET world. Since .NET Core 3 and ASP.NET Core 3 Microsoft introduced a new one named System.Text.Json. JObject is a class that belongs to Json.Net (NewtonSoft) and if this latest is replaced by System.Text.Json, in this case you should expect that using JObject will no longer work. Unfortunately I have had to deal with JObject in request payloads and in this article I will show you how to live without JObject and how replace it without breaking your application.
Before in ASP.NET Core 2+
As I said before, in previous version of ASP.NET Core 3 the serialization was done with Json.Net (NewtonSoft) and I have had to deal with json payload not stringified, so the only solution was to use JObject as model for the request payload databinding like this:
Since ASP.NET Core 3
The previous case doesn’t work anymore unless if you decide to use Json.Net (NewtonSoft) as default JSON Serializer, so you have to download that package which enables it:
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.3
This is not what I recommand, because you will loose a big advantage advantage brought by System.Text.Json: a better performance !
So we need to explore System.Text.Json to find a solution, and the solution is JsonElement. JsonElement is a struct that represents a specific JSON value within a JsonDocument. How to enable it ?
You don’t have anything to do, except import into your controller the assembly named “System.Text.Json”
As you can see it’s easy to get data in the desired type, JsonElement exposes methods to get any types:
GetBoolean() | Gets the value of the element as a Boolean. |
GetByte() | Gets the current JSON number as a Byte. |
GetBytesFromBase64() | Gets the value of the element as a byte array. |
GetDateTime() | Gets the value of the element as a DateTime. |
GetDateTimeOffset() | Gets the value of the element as a DateTimeOffset. |
GetDecimal() | Gets the current JSON number as a Decimal. |
GetDouble() | Gets the current JSON number as a Double. |
GetGuid() | Gets the value of the element as a Guid. |
GetInt16() | Gets the current JSON number as an Int16. |
GetInt32() | Gets the current JSON number as an Int32. |
GetInt64() | Gets the current JSON number as an Int64. |
GetProperty(ReadOnlySpan<Byte>) | Gets a JsonElement representing the value of a required property identified by utf8PropertyName . |
GetProperty(ReadOnlySpan<Char>) | Gets a JsonElement representing the value of a required property identified by propertyName . |
GetProperty(String) | Gets a JsonElement representing the value of a required property identified by propertyName . |
GetRawText() | Gets a string that represents the original input data backing this value. |
GetSByte() | Gets the current JSON number as an SByte. |
GetSingle() | Gets the current JSON number as a Single. |
GetString() | Gets the value of the element as a String. |
GetUInt16() | Gets the current JSON number as a UInt16. |
GetUInt32() | Gets the current JSON number as a UInt32. |
GetUInt64() | Gets the current JSON number as a UInt64. |
Demo
Payload used on the demo:
Execution:
Hope this article helped you 😉