Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why do I have to define a property when deserializing json with System.Text.Json? #33766

Open
opcodewriter opened this issue Jul 4, 2023 · 4 comments
Assignees
Labels
Area-NetSDK untriaged Request triage from a team member

Comments

@opcodewriter
Copy link

opcodewriter commented Jul 4, 2023

A simple class with a c-tor like this:

    class Result
    {
        public Result(string error)
        {
        }
    }

and the json:

        var json ="""
            {
                "error": "some error"
            }
            """;
 var result = JsonSerializer.Deserialize<Result>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web));

throws an exception at runtime saying I don't have a property or field defined in the class.

So if I add a property like this:

    class Result
    {
        public string Error { get; }

        public Result(string error)
        {
        }
    }

the exception is not thrown anymore. I correctly receive the "some error" string in the c-tor. However, I don't care to set the property at all.

I know that if I don't want to have a property or field defined in the class, I need to implement a custom JsonConverter<Result>, so how to solve this is not my question.

My question is: Since the deserialization logic is perfectly capable of mapping the error JSON field to the error parameter of the c-tor, why is the property required?

You might ask, why would I NOT want to have a property or a field defined?

Because, in a scenario where the response is a bit more dynamic, I'd like to be able to map the c-tor parameter to something else, without having to have something more complicated like a custom JsonConverter:

        class Result
        {
            // Useless property just to make the deserialization work
            public Dictionary<string, Item> Data { get; }

            public Item Item { get; }

            public Result(Dictionary<string, Item> data)
            {
                Item = data.Values.Single();
            }
        }

        class Item
        {
            public int Id { get; }
            public Item(int id) => Id = id;
        }
{
    "data" : {
         "dynamic_name": { "id" : 1 }
     }
}
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-NetSDK untriaged Request triage from a team member labels Jul 4, 2023
@KalleOlaviNiemitalo
Copy link
Contributor

dotnet/runtime#44428 (comment) proposes a setting that would remove the requirement to define a property for each parameter of the constructor.

@opcodewriter
Copy link
Author

opcodewriter commented Jul 4, 2023

@KalleOlaviNiemitalo wow, thanks a lot. Although the OP's issue seems a bit different (the property is of another type than the c-tor parameter's type), the root cause is the same.

I don't understand why it was necessary to enforce having a property, when the deserialization logic can just find the c-tor parameter.

@KalleOlaviNiemitalo
Copy link
Contributor

I imagine they wanted serialization and deserialization to use the same property names.

@opcodewriter
Copy link
Author

opcodewriter commented Jul 4, 2023

@KalleOlaviNiemitalo Hmm, I see what you're saying but why would the serialization and deserialization be coupled in any way? For example, in my scenario, I don't even need serialization, but only deseralization.

I'm sure they have a good reason, they are way smarter than I am 😀 I just need to understand what is it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-NetSDK untriaged Request triage from a team member
Projects
None yet
Development

No branches or pull requests

3 participants