Despite .NET Core 3 Deprecation, Newtonsoft JSON Serializer Still Rules NuGet Roost
Despite being deprecated by Microsoft in .NET Core 3.0, the wildly popular Newtonsoft.Json JSON serializer still rules the roost in the NuGet package manager system for .NET developers.
By comparison, the second-most downloaded package is the serilog .NET logging tool, at nearly 12 million downloads.
Yet Newtonsoft.Json was basically scrapped by Microsoft with the coming of .NET Core 3.0 in favor of its newer offering designed for better performance, System.Text.Json.
In describing the future of JSON in .NET Core 3.0, Immo Landwerth last year said the following about Json.NET, from Newtonsoft:
"JSON has become an essential part of virtually all modern .NET applications and in many cases even surpassed the usage of XML. However, .NET hasn't had a (great) built-in way to deal with JSON. Instead, we've relied on Json.NET until now, which continues to serve the .NET ecosystem well.
"We've decided that we needed to build a new JSON library:
- Provide high-performance JSON APIs. We needed a new set of JSON APIs that are highly tuned for performance by using Span and can process UTF-8 directly without having to transcode to UTF-16 string instances. Both aspects are critical for ASP.NET Core, where throughput is a key requirement. We considered contributing changes to Json.NET, but this was deemed close to impossible without either breaking existing Json.NET customers or compromising on the performance we could achieve. With System.Text.Json, we were able to gain 1.3x – 5x speed up, depending on the scenario (see below for more details). And we believe we can still squeeze out more.
- Remove Json.NET dependency from ASP.NET Core. Today, ASP.NET Core has a dependency on Json.NET. While this provides a tight integration between ASP.NET Core and Json.NET, it also means the version of Json.NET is dictated by the underlying platform. However, Json.NET is frequently updated and application developers often want to -- or even have to -- use a specific version. Thus, we want to remove the Json.NET dependency from ASP.NET Core 3.0, so that customers can choose which version to use, without fearing they might accidentally break the underlying platform.
- Provide an ASP.NET Core integration package for Json.NET. Json.NET has basically become the Swiss Army knife of JSON processing in .NET. It provides many options and facilities that allow customers to handle their JSON needs with ease. We don't want to compromise on the Json.NET support customers are getting today. For example, the ability to configure the JSON serialization in ASP.NET Core via the AddJsonOptions extension method. Thus, we want to provide the Json.NET integration for ASP.NET Core as a NuGet package that developers can optionally install, so they get all the bells and whistles they get from Json.NET today. The other part of this work item is to ensure we have the right extension points so that other parties can provide similar integration packages for their JSON library of choice.
Early this year Microsoft published guidance on "How to migrate from Newtonsoft.Json to System.Text.Json."
But that doesn't seem to have had much effect yet, as System.Text.Json is averaging 11,525 NuGet downloads per day, which to to date have totaled 27,765,461 downloads.
Newtonsoft.Json, meanwhile, is averaging 164,895 per day for a total of 575,486,369.
Note that NuGet doesn't tell the whole story, however, as the System.Text.Json library is included in the .NET Core 3.0 shared framework, while for other target frameworks, developers need to install the System.Text.Json NuGet package.
Still Newtonsoft.Json seems to be holding its own despite Microsoft's efforts to move on.
While serialzing/deserializing data over the web in ASP.NET Core applications might not seem to be that important for most developers, Michael Shpilt called the addition of System.Text.Json into .NET Core 3 a "big deal" in a post late last year.
"If you've been working with .NET for some time, then you should know the excellent Json.NET serializer, also known as Newtonsoft.Json. So why do we need a new serializer if we already got Newtonsoft.Json? While Newtonsoft.Json is great, there are several good reasons to replace it:"
- Microsoft wanted to make use of the new types like Span<T> to improve performance. Modifying a huge library like Newtonsoft without breaking functionality is very difficult.
- Most network protocols, including HTTP, use UTF-8 text. The type string in .NET is UTF-16. Newtonsoft transcodes UTF-8 into UTF-16 strings in its work, compromising performance. The new serializer uses UTF-8 directly.
- Since Newtonsoft is a 3rd party library and not part of the .NET Framework (BCL or FCL classes), you might have projects with dependencies on different versions. ASP.NET Core itself is dependent on Newtonsoft, which results in many version conflicts."
Spencer Schneidenbach also examined the issue in a January post, comparing the two options and offering this TL;DR:
System.Text.Json is a new JSON library for .NET with different design goals from its predecessor, Newtonsoft.Json. If you're already using Newtonsoft.Json in an existing project, you likely don't need to switch. If you absolutely need high JSON serialization/deserialization performance, go with System.Text.Json.
Going into the details, Schneidenbach noted that because System.Text.Json strictly adheres to the JSON spec, RFC 8259 - things that developers previously could do with Newtonsoft.Json (because it wasn't spec-compliant) aren't allowed in System.Text.Json.
Specifically, he said Newtonsoft.Json will deserialize:
- Property names that have a different case
- Property names in JSON that have single/double/no quotes
- Null values for non-nullable fields properties (null -> an int property is allowed)
Schneidenbach said System.Text.Json, meanwhile, only provides out-of-the-box support for:
- Deserializing JSON properties by names with the same case
- Property names with double quotes
- Deserializing JSON properties to their like-typed C# counterparts (int -> int only, not null -> int property)
Microsoft's own documentation, meanwhile, provides a much longer list of differences between the two tools and what they can do, along with workarounds to duplicate the functionality of Newtonsoft.Json.
"System.Text.Json focuses primarily on performance, security, and standards compliance," Microsoft says. "It has some key differences in default behavior and doesn't aim to have feature parity with Newtonsoft.Json. For some scenarios, System.Text.Json has no built-in functionality, but there are recommended workarounds. For other scenarios, workarounds are impractical. If your application depends on a missing feature, consider filing an issue to find out if support for your scenario can be added."
Landwerth's June 2019 post drew an unusually large number of comments -- 73 in total -- and not all of the them were supportive of the switch from Newtonsoft.Json to System.Text.Json.
"Ok, so just like always, you built your own, which will be substandard, incompatible, and slower for real world cases," one comment said. "I bet your contrived examples were faster… publish all the real world cases that came in slower ... in the interest of full disclosure.
"And to top it off, you wrote it into System.Text.Json namespace, so now we'll usually have two JSON libraries deployed: JSON.net and yours.
"Brilliance! Classic Microsoft 'Not Invented Here' syndrome that plagues the entire MS infrastructure. Note how the worst security bugs are mostly Microsoft's? There's an underlying symptom for that ... and its because you keep copying other people's stuff and trying to write it better, while not understanding the reasons for why that stuff exists in the first place."
Another comment was more benign: "Honestly, it seems like a solution in search of a problem. We've been using the newtonsoft product for years and it's one of the few modules that has never caused us problems. But, whatever. I just hope it doesn't cause conflicts."
David Ramel is an editor and writer for Converge360.