quicktype icon indicating copy to clipboard operation
quicktype copied to clipboard

Support for .Net Core 3 Json library

Open monsieurleberre opened this issue 4 years ago • 18 comments

.Net Core 3 comes with its own set of classes to serialise and deserialise JSON, located in the System.Text.Json and System.Text.Json.Serialization. Previous versions used to rely on Newtonsoft.Json and Newtonsoft.Json.Converters instead.

This also means some attribute names need to be adapted:

        [JsonProperty("id")]
        public Guid Id { get; set; }

becomes

        [JsonPropertyName("id")]
        public Guid Id { get; set; }

Serialisation of enums to string can be done this way

    [JsonConverter(typeof(JsonStringEnumConverter))]
    public enum Color { Red, Green, Blue };

but cannot be done by involving JsonReader and JsonWriter like it was in previous versions.

It would be nice to be able to choose between Newtonsoft.Json and System.Text.Json when using quicktype to create classes from Json.

Here is a good starting place to understand the changes I am refering to: https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#fast-built-in-json-support

Cheers!

monsieurleberre avatar Nov 19 '19 13:11 monsieurleberre

Love this idea! We would be happy to guide someone in contributing this as an option to the existing C# language support.

dvdsgl avatar May 31 '20 18:05 dvdsgl

any news about supporting System.Text.Json?

Gambero81 avatar Oct 26 '20 10:10 Gambero81

@dvdsgl ... I (potentially) volunteer as tribute! image

Can you share any contribution guidelines/tips/insight? I'm in that brief window of time where I'm trying to decide if it would be easier to just change the generated code, or contribute this change to pay it forward :P

joelmartinez avatar Mar 23 '21 01:03 joelmartinez

@joelmartinez do it! I'll help you if you get stuck. Should not be too bad.

See how we support many different serialization frameworks in Kotlin. Just make it an option, then we'll create some high-level helpers that emit the right code depending on which framework you're using.

dvdsgl avatar Mar 23 '21 01:03 dvdsgl

Can't wait for this!! 👍

Jacko1394 avatar Apr 23 '21 04:04 Jacko1394

@joelmartinez Do you have any progress on this issue?

doggy8088 avatar Jun 15 '21 06:06 doggy8088

@doggy8088 image

Unfortunately, my "brief window of time" ended up going in another direction ... I never got quite deep enough into implementation territory here. So the task is still open for anyone else that wants a crack.

joelmartinez avatar Jun 15 '21 14:06 joelmartinez

Any news?

CrAcK75 avatar May 07 '22 09:05 CrAcK75

I got quicktype running with the code from the PR, seems to work fine as is for at least my needs. Is there any progress as to getting this included?

bzuidgeest avatar Jul 18 '22 19:07 bzuidgeest

@bzuidgeest You might consider use my version of quicktype.

Source: https://github.com/doggy8088/quicktype/tree/CSharp-SystemTextJson

npm: @willh/quicktype

doggy8088 avatar Jul 19 '22 08:07 doggy8088

@bzuidgeest You might consider use my version of quicktype.

Source: https://github.com/doggy8088/quicktype/tree/CSharp-SystemTextJson

npm: @willh/quicktype

I already made a version for myself based on your code. much nicer output then njsonschema.

I got it compiling and working on linux on an old laptop. But I can't seem to get it to compile on windows and that is where I need it. All kinds of weird errors with packages an dependencies. I develop in c#, nodejs and npm are alien to me. Though i could read and modify the typescript code. Its close to javascript en very readable.

I do wonder why you create a converter for enum?. .net 5 and 6 both have the build in stringenumconverter.

bzuidgeest avatar Jul 19 '22 10:07 bzuidgeest

It because JsonStringEnumConverter doesn't fit my need on certain circumstance.

doggy8088 avatar Jul 19 '22 10:07 doggy8088

It because JsonStringEnumConverter doesn't fit my need on certain circumstance.

That much was obvious. But not very helpfull. I do know it has an "issue" arround nullable enums, but personally I find enums should not be nullable, if you don't know the value a "unknown" option should be added to the enum. But opinions like that are personal and I cannot expect everyone to share them. Was this your "circumstance"?

bzuidgeest avatar Jul 19 '22 11:07 bzuidgeest

@bzuidgeest I took some time to remember what's my circumstance. 😅

I have a json like this.

[
    {
        "name": "Will",
        "department": "CorpA.General",
        "age": "18"
    },
    {
        "name": "Mary",
        "department": "CorpB.Finance",
        "age": "19"
    }
]

The department must be an Enum type, but the value can't be a Enum options because there is a dot (.) in it. Let's why I can't use JsonStringEnumConverter as my default enum's converter.

Here is my sample code that can run under LINQPad 7.

void Main()
{
    var serializerOptions = new JsonSerializerOptions
    {
        Converters = {
            DepartmentConverter.Singleton
        },
        NumberHandling = JsonNumberHandling.AllowReadingFromString,
        WriteIndented = true
    };

    var jsonPath = Util.CurrentQueryPath.Replace(".linq", ".sample.json");
    var jsonText = File.ReadAllText(jsonPath);

    var user = JsonSerializer.Deserialize<UserProfile[]>(jsonText, serializerOptions);

    user.Dump();

    string json = JsonSerializer.Serialize(user, serializerOptions);

    json.Dump();
}

public class UserProfile
{
    [JsonPropertyName("name")]
    public string Name { get; set; }

    [JsonPropertyName("department")]
    public Department Department { get; set; }

    [JsonPropertyName("age")]
    public int Age { get; set; }
}

public enum Department
{
    CorpA_General,
    CorpB_Finance
};


public class DepartmentConverter : JsonConverter<Department>
{
    public override bool CanConvert(Type t) => t == typeof(Department);

    public override Department Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var value = reader.GetString();
        switch (value)
        {
            case "CorpA.General":
                return Department.CorpA_General;
            case "CorpB.Finance":
                return Department.CorpB_Finance;
        }
        throw new Exception("Cannot unmarshal type Department");
    }

    public override void Write(Utf8JsonWriter writer, Department value, JsonSerializerOptions options)
    {
        switch (value)
        {
            case Department.CorpA_General:
                JsonSerializer.Serialize(writer, "CorpA.General");
                return;
            case Department.CorpB_Finance:
                JsonSerializer.Serialize(writer, "CorpB.Finance");
                return;
        }
        throw new Exception("Cannot marshal type Department");
    }

    public static readonly DepartmentConverter Singleton = new DepartmentConverter();
}

As this doc The Support enum string value deserialization:

It works without a specified naming policy or with the CamelCase naming policy. It doesn't support other naming policies.

My custom converter support every circumstances and make sure Read and Write are identical.

doggy8088 avatar Jul 19 '22 15:07 doggy8088

Would be amazing to have this option built in to replace Json.NET.

dylanvdmerwe avatar Jul 26 '22 12:07 dylanvdmerwe

@doggy8088 That seems like an excellent reason for doing it the way you did. The use case is rather specifc however (I think) and I don't know if it would hold up in a general use tool. What if the next person would use a different seperator and a different way of correcting it in the conversion. For example what if the replaced the dot in the enum by removing it al together? You would have to define a lot of use cases.

But thanks for explaining, that is very usefull.

bzuidgeest avatar Jul 26 '22 12:07 bzuidgeest

@dylanvdmerwe Replace is a bad option. A lot of people have invested in the code as-is and rely on it. Also JSON.net is far from dead. It might fade eventually, but for now its still heavily used and has unique features that are not in System.Text.Json and might never be available there. Personally I am a proponent of what @dvdsgl suggested. The Kotlin generator has an option to choose the framework to be used. We should have that for C# to.

I looked into the code files and we could copy the way kotlin does it and then cobine @doggy8088 repo his generator code with the existing generator code. Some name clashes would need to be fixed, but it should not be to difficult. Basically two generators and a choice between the two.

bzuidgeest avatar Jul 26 '22 12:07 bzuidgeest

@bzuidgeest agreed my apologies I meant that having the option to select which generator to use would be incredible.

dylanvdmerwe avatar Jul 26 '22 12:07 dylanvdmerwe

I took the code from the repo of @doggy8088 and merged it with the current version of quicktype using the kotlin generator as an example of how to implement selecting between frameworks. Just like @dvdsgl sugested It seems to work but I need to mention some caveats.

  • I am NO typescript developer. But code is code so I think I did a reasonable job putting everything in place.
  • The csharp testsuite still runs OK, so at least I did not break the existing stuff. But I don't know how to add a test project that can test the SystemTextJson framework to the project. Someone will have to point out what needs to happen. Could be the test docker container provided needs to be supplied with a newer .NET version, new test project etc...

code is here: https://github.com/bzuidgeest/quicktype/tree/SystemTextJson I could make a pull request, but I doubt that would be accepted without tests. Maybe I make one for show.

bzuidgeest avatar Sep 28 '22 14:09 bzuidgeest

So I committed number of changes and as far as I can determine most tests run fine. Even some that are excluded with newtonsoft lib because of framework issues. Seems reasonable to me. Lets hope someone actually want to take a look at the PR

bzuidgeest avatar Oct 02 '22 19:10 bzuidgeest

Why is this not a thing yet? .net 6 does not even have newtonsoft

Bluscream avatar Oct 18 '22 22:10 Bluscream

Why is this not a thing yet? .net 6 does not even have newtonsoft

That is nonsense, Newtonsoft Json.net library always has been a sperate lib and is very much supported on .NET6. Just as normal with the nuget package. The fact that Microsoft included it (the nuget) by default in some templates has no bearing on that.

With the latest .net you are free to choose between the system.text.json and newtonsoft libs.

That said, this project seems to be "on hold" as in the discussions you can read the maintainers do not have the time to maintain it. Wish I new that before I create my branch and PR.

bzuidgeest avatar Oct 19 '22 11:10 bzuidgeest

Fixed in #1997

dvdsgl avatar Jan 04 '23 06:01 dvdsgl