John McArthur
John McArthur

Reputation: 1024

Json Deserialization not working in F# using Newtonsoft.Json after upgrade to .Net 6

These are my types:

[<DataContract>]
type AreaCodeSingleResponse = 
    { [<field:DataMember(Name = "id")>]
      Id : string
      [<field:DataMember(Name = "code")>]
      Code : string
      [<field:DataMember(Name = "name")>]
      Name : string }

[<DataContract>]
type AreaCodeListResponse = 
    { 
    [<field:DataMember(Name = "areacode_list")>]
      AreaCodeList : List<AreaCodeSingleResponse> }

This is a sample of the data:

{
    "areacode_list": [
        {
            "id": "00447",
            "code": "07",
            "name": "UK Mobile",
            "order_column": "_00447"
        },
        {
            "id": "0044113",
            "code": "0113",
            "name": "Leeds",
            "order_column": "0044113"
        }
    ]
}

This is the deserialization code, where It's called passing in the type AreaCodeListResponse:

member __.ReturnDataToType<'T>() =
    __.ReturnData
    |> JsonConvert.DeserializeObject<'T>

Before I upgraded to DotNet6 this worked fine and returned a list of data. Afterwards, it fails and returns an empty list. There are no errors thrown but the list is empty.

This is failing for all my other calls to deserialize using the class and other types.

Has anything changed that I need to be aware of? I'm not a F# expert, just picking it up working on some legacy code.

Upvotes: 5

Views: 447

Answers (1)

jpe
jpe

Reputation: 1021

There seems to be a behavioural change in how the .Net runtime handles the OptionalFieldAttribute (used as field: in F#) in .Net 7 (in conjunction with F# records). When looking into the documentation of OptionalFieldAttribute then it should have no meaningful effect in the context of JSON serialization/deserialization and thus should be removed. The following code works by producing a list of AreaCodeSingleResponse record instances. The minimal modification to make the code in the question work is to remove the OptionalFieldAttribute from the AreaCodeList field.

#r "nuget:Newtonsoft.Json,Version=13.0.2"

open System.Runtime.Serialization
open Newtonsoft.Json

[<DataContract>]
type AreaCodeSingleResponse = 
    { 
      [<DataMember(Name = "id")>]
      Id : string
      
      [<DataMember(Name = "code")>]
      Code : string
      
      [<DataMember(Name = "name")>]
      Name : string
      }

[<DataContract>]
type AreaCodeListResponse = 
    { 
      //Remove the OptionalFieldAttribute:
      //[<field:DataMember(Name = "areacode_list")>]
      [<DataMember(Name = "areacode_list")>]
      AreaCodeList : List<AreaCodeSingleResponse>
    }


let ReturnData = """{
    "areacode_list": [
        {
            "id": "00447",
            "code": "07",
            "name": "UK Mobile",
            "order_column": "_00447"
        },
        {
            "id": "0044113",
            "code": "0113",
            "name": "Leeds",
            "order_column": "0044113"
        }
    ]
}"""
ReturnData |> JsonConvert.DeserializeObject<AreaCodeListResponse> |> printf "%A"

The question why this behavioural change happens when moving from .Net runtime 6.0.201 to .Net 7.0.101 remains open.

Upvotes: 2

Related Questions