dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.27k stars 4.73k forks source link

Support "dynamic" and writable DOM #29690

Closed justinushermawan closed 3 years ago

justinushermawan commented 5 years ago

Does JsonSerializer.Parse(String, Type, JsonSerializerOptions) support for dynamic ExpandoObject return type?

Something like this: dynamic p = JsonSerializer.Parse(json, typeof(ExpandoObject));

keithn commented 3 years ago

Seems weird C# doesn't have a standard library to manipulate JSON data, only serialize, deserialize from static types, or read only an arbitrary json document. Really need to be able to read, query and to manipulate JsonDocument, add elements, remove elements, etc and then turn it back to a string. The simple pain of getting any arbitrary piece of json and adding an extra element to it is astonishing. Think you guys need to implement a library that allows full manipulation of JSON data, not just a means to and end for deserializing/serializing static types.

rs38 commented 3 years ago

in .NET there are 2 standards: 3rd party Nuget package Json.NET and .NET Core’s built-in classes System.Text.JSON which are very fast but a bit limited compared to Json.NET.

here is an example of manipulating a JSON file without deserializing with the built in Json classes:

using var json = File.OpenRead (jsonPath);
using JsonDocument document = JsonDocument.Parse (json);
var options = new JsonWriterOptions { Indented = true };
using (var outputStream = File.Create ("NewFile.json"))
using (var writer = new Utf8JsonWriter (outputStream, options))
{
 writer.WriteStartArray();
 foreach (var person in document.RootElement.EnumerateArray())
 {
 int friendCount = person.GetProperty ("Friends").GetArrayLength();
 if (friendCount >= 2)
 person.WriteTo (writer);
 }
}

(from: C# 8.0 in a Nutshell)

udlose commented 3 years ago

As promised, the PR providing a dynamic implementation sample is at #42097.

@steveharter - I'm unable to get your PR Code sample for supporting dynamic objects #42097 to load consistently - most of the time it won't load.

I also noticed that the example is missing a ToString() implementation override on JsonDynamicString - was this intentional? I'm planning on adding the override but don't want to rely on it if the final implementation in 6.0 won't use it.

image

John0King commented 3 years ago

Am I the only one who want a JSON POCO Object in C# (eg. JToken) , so we can manipulate the "object" easily and also other Json library can directly handle it too.

and @rs38 you solution is about write, and a mutable JSON DOM is about change and read (or write)

//  do some change to the original JSON
var jobj = xxxx.Parse(Request.Body) as JObject;
if(ShouldInjectClaim == true)
{

   jobj.Add("Claims", JArray.Parse(new []{  "claim1". "claim2" }));
}

//  handle the "data"
DoSomething(jobj);  // mostly read again
ericstj commented 3 years ago

@John0King I don't think you're the only person, that's part of what this issue is about. Have you seen https://github.com/dotnet/designs/pull/163?

@udlose not sure why GitHub is having trouble loading the PR. You can always check out the commit: https://github.com/dotnet/runtime/commit/095539fd800775fc9542a07f411cbc1b7e72084e or even just browse to these tests that are now part of the product.

I also noticed that the example is missing a ToString() implementation override on JsonDynamicString - was this intentional?

I think that's just because the sample was minimal. I see @steveharter mentions this in the design doc: https://github.com/dotnet/designs/pull/163/files#diff-34fc37119c1d4491b844207aeed3a9c846c3e2d835fd712e164b1e47b89687c0R77

steveharter commented 3 years ago

Closing; the JsonNode feature is in main and will be in Preview 4.

Preview 5 will also add some new capabilities for JsonObject including deterministic property ordering and being able to use JsonObject as an "extension property" via [JsonExtensionDataAttribute]. These are mentioned in the PR description.

udlose commented 3 years ago

@steveharter , @ericstj I pulled Steve's code sample for supporting dynamic from https://github.com/dotnet/runtime/commit/095539fd800775fc9542a07f411cbc1b7e72084e. It worked fine when I was running under .NET Core 3.1. I'm upgrading the app to .NET 5 and getting an error:

JsonSerializerExtensions.JsonDynamicType.Value is inaccessible due to its protection level

I can easily change these from internal to public but I'm concerned about why it broke when migrating to .NET 5. Is there a new version of the code sample that works for .NET 5?

ericstj commented 3 years ago

It looks to me like a compiler error around a identifier resolution, where something in another assembly is resolving to that Value member when it didn't before. It could be something unrelated to the update. If you have an issue to report (even against sample code) it's better to open a new issue and provide us with full details and a repro, that way we can better reproduce and diagnose what you are seeing.

Also, if you're willing to grab a nightly build you can try the official feature which is in as of last week: https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet6&package=System.Text.Json&protocolType=NuGet&version=6.0.0-preview.5.21229.9

Thanks!

techhowdy commented 3 years ago

You can also try this

var obj = JsonDocument.Parse(Convert.ToString(your_dynamic_object));

 var propertyVal = obj.RootElement.GetProperty("Your_Property_Name").GetString();
steveharter commented 3 years ago

For those still interested in dynamic how valuable is that now that we have a writable DOM with JsonNode?

Please add your comments to this issue: https://github.com/dotnet/runtime/issues/53195