5

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.

dbc
  • 104,963
  • 20
  • 228
  • 340
John McArthur
  • 916
  • 1
  • 12
  • 30
  • 1
    Any chance you ended up switching to System.Text.Json from Newtonsoft without realizing it? You don't say what version you upgraded **from**, but in [tag:asp.net-core-3.0] Microsoft abandoned Json.NET and switched to its new JSON serializer, System.Text.Json. See: [Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0?](https://stackoverflow.com/q/55666826/3744182). And System.Text.Json doesn't support f# well, see e.g. [Serialize Record members with System.Text.Json](https://stackoverflow.com/q/72656832) and https://github.com/dotnet/runtime/issues/55744. – dbc Dec 23 '22 at 19:28
  • No, definitely using JSON.net, it's specifically referenced in the code – John McArthur Dec 24 '22 at 15:16
  • 1
    I don't have f# on .NET 6 to test, but what if you change `[]` to `[]`? – dbc Dec 24 '22 at 18:06
  • Actually, the breaking change seems to occur when moving from .net 6.0 to 7.0. Your approach works for me with Newtonsoft.Json versions 13.0.2, 12.0.3 and 11.0.2 (did not try earlier ones) in .net 6.0, but no longer in .net 7.0. What is the result of `dotnet --version` in your environment? – jpe Dec 29 '22 at 17:05

1 Answers1

2

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.

jpe
  • 1,013
  • 6
  • 14