AJP.JsonElementExtensions 1.8.0

dotnet add package AJP.JsonElementExtensions --version 1.8.0                
NuGet\Install-Package AJP.JsonElementExtensions -Version 1.8.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AJP.JsonElementExtensions" Version="1.8.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AJP.JsonElementExtensions --version 1.8.0                
#r "nuget: AJP.JsonElementExtensions, 1.8.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install AJP.JsonElementExtensions as a Cake Addin
#addin nuget:?package=AJP.JsonElementExtensions&version=1.8.0

// Install AJP.JsonElementExtensions as a Cake Tool
#tool nuget:?package=AJP.JsonElementExtensions&version=1.8.0                

JsonElement.Extensions

Azure DevOps builds Nuget Nuget

What is it?

A collection of extension methods for System.Text.Json.JsonElement, for adding/removing properties dynamically

Why is it needed?

JsonElement is immutable, which is good, but lots of people have use case involving deserializing to a dynamic or JObject in order to 'tweak' an object thats returned from an API etc. There is currently no support for using dynamics with the serializers in System.Text.Json and wont be until after dotnet5. So I thought I'd try to fill the gap, at least temporarily.

How does it work?

So, these methods work by enumerating the existing properties of the JsonElement and then writing them into a new json string in memory with additional properties added or existing properties removed along the way. The resulting string is parsed into a new JsonElement which is returned. The original JsonElement is obviously unchanged. Hopefully the methods are fairly self explanatory and are well documented in the tripple slash comments.

How to use it?

var jsonString = "{ \"Name\": \"Andrew\", \"EmailAddress\": \"a@b.com\" }";
var jElement = JsonDocument.Parse(jsonString).RootElement;

jElement = jElement.AddProperty("isAdmin", true); // Remember to re-assign the return value, as it is a new JsonElement, i.e. the current one doesn't change
jElement.ToString().Dump(); // yields {"isAdmin":true,"Name":"Andrew","EmailAddress":"a@b.com"}

Bulk updates

Please note this roundtrip process happens for every call, so if lots of changes are needed, please consider/test using ParseAsJsonStringAndMutate() which enables multiple changes to be made, with only one roudtrip process. This method provides an Action<Utf8JsonWriter, List<string>> the Utf8JsonWriter can be used to write additional properties (which will end up at the start of the list of properties) and the List<string> is a list of existing property names to skip when writing out the properties.

Preserving property order

The recently added Insert(), InsertNull() and Update() methods all use ParseAsJsonStringAndMutatePreservingOrder() under the hood. ParseAsJsonStringAndMutatePreservingOrder() first enermurates the JsonElement and then provides an Action<PropertyList> allowing the caller to mutate the list while preserving the order of the list, the mutated list is then enumerated to write the mutated properties into the new json string. Hence these methods are slightly more expensive in terms of speed and allocation than the non-order preserving counterparts (AddProperty(), AddNullProperty(), RemoveProperty() and ParseAsJsonStringAndMutate()).

|                    Method |     Mean |     Error |    StdDev |   Median |  Gen 0 |  Gen 1 | Gen 2 | Allocated |
|-------------------------- |---------:|----------:|----------:|---------:|-------:|-------:|------:|----------:|
|                  MutateV1 | 1.601 us | 0.0316 us | 0.0511 us | 1.593 us | 0.2060 |      - |     - |      1 KB |
| MutateV2_preserving_order | 3.013 us | 0.2588 us | 0.7549 us | 2.683 us | 0.6256 | 0.0038 |     - |      4 KB |

License

Feel free to use for whatever - MIT license. If its usefull please let me know!

Contributing

Contributions would be most welcome! the only thing I ask is that new features are covered by minimal unit tests, along the same lines as the existing ones. Please create a PR.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on AJP.JsonElementExtensions:

Package Downloads
AJP.MediatrEndpoints

Small library which wires up aspnetcore endpoints to MediatR request handlers.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.8.0 117 10/22/2024
1.7.0 20,745 10/22/2022
1.6.0 26,982 8/9/2021
1.5.0 4,064 6/12/2021
1.4.0 1,446 5/23/2021
1.3.0 2,507 2/28/2021
1.2.0 480 2/28/2021
1.1.0 2,819 2/29/2020
1.0.0 685 2/28/2020

1.8.0) upgrade to net8.0 and latest packages
   1.7.0) upgrade to net6.0 and latest packages
   1.6.0) added support for JsonElements when adding/updating properties, thanks to leandrosilva
1.5.0) added InsertProperty, UpdateProperty and ParseAsJsonStringAndMutatePreservingOrder methods and associated tests
1.4.0) added support for IEnumerables, nested objects, better handle null values, thanks to hanabanashiku
1.3.0) targetting netstandard2.1 in order to make of spans and added ConvertToObject methods
1.2.0) fixed issue where primitive style objects passed in as object were treated incorrectly
1.1.0) changed target framework to netstandard2.0
1.0.0) initial version