question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using Newtonsoft.Json with F# records can lead to NullReferenceExceptions down the line instead of failing fast when deserialising in case of types mismatch

See original GitHub issue

Source/destination types

These records:

type Foo1 =
    {
        Bar: int
        Baz: string
    }

type Foo2 =
    {
        BarBaz: Foo1
        Baz: string
    }

Steps to reproduce

    let foo1 = { Bar = 69; Baz = "oof" }
    let foo1json = JsonConvert.SerializeObject foo1
    Console.WriteLine ("serialized foo1:" + foo1json)
    let foo2 = JsonConvert.DeserializeObject<Foo2> foo1json

    Console.WriteLine ("foo2.Baz==" + foo2.Baz)

    let isBarBazNull = Object.ReferenceEquals(foo2.BarBaz, null)
    Console.WriteLine ("foo2.BarBaz==null?" + isBarBazNull.ToString())

Actual behavior

The following is printed:

serialized foo1:{"Bar":69,"Baz":"oof"}
foo2.Baz==oof
foo2.BarBaz==null?True

Which means that examining foo2.BarBaz.Bar could throw a NullReferenceExceptions, when precisely F# is a language that presumes to not have this kind of exceptions. Newtonsoft.Json should be fixed to not make F# worse 😃

Expected behavior

The line JsonConvert.DeserializeObject<Foo2> foo1json should throw an exception because the members of the json document don’t match with the members of the record type.

Versions tested with: 11.0.2 and 12.0.2

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:2
  • Comments:5

github_iconTop GitHub Comments

3reactions
baronfelcommented, Aug 6, 2019

Point of clarification: the code examples in the first message are describing records not discriminated unions.

I have this problem as well, and I believe it’s emblematic of problems with F# records and serialization:

  • the current algorithm creates an ‘empty’ instance of the type, which for F# may not be valid. I’d argue that f# records do not have a valid ‘empty’ state.
  • The proper algorithm would be to use the FSharpType and FSharpValue module functions to do something like the following:
    • determine if the destination type is a record via FSharpType.IsRecordType. if no, continue on current serialization strategy. if yes,
    • get field information for the record and iterate through them, deserializing each property from the current json payload to get the final array of record fields
    • use FSharpValue.MakeRecord with the appropriate type and field arguments to create a fully-hydrated and correct record with no missing fields.

Over the process of making the field value array, optionality should be taken into account. IE if destination type is 'a option and the key is not present, set None for that value. Any other missing value should be interpreted as a serialization failure, because F# records are more strict than C# classes.

0reactions
knoctecommented, Aug 7, 2019

records not discriminated unions.

D’oh! just changed this thanks.

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - When using record types to deserialize JSON, how can ...
I am using Newtonsoft Json to deserialize JSON into C# record types. I'll provide examples below, but the theme of the challenge here...
Read more >
Performance Tips
Here are some tips to make it go even faster. Reuse Contract Resolver; Optimize Memory Usage; JsonConverters; Manually Serialize; Benchmarks. Reuse Contract ...
Read more >
Error when Deserialize Json Array - Help
Json.Linq.JArray'. Type mismatch could be due to mixing a file reference to 'C:\Users\Dell.nuget\packages\newtonsoft.json ...
Read more >
Serialization Error Handling
The Error event is an event handler found on JsonSerializer. The error event is raised whenever an exception is thrown while serializing or...
Read more >
How to Deserialize a Complex JSON Object in C# .NET
In this article, we are gonig to learn how to deserialize a complex JSON object using C# as our language of choice.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found