jsoncollectionsf#datacontractjsonserializer

JSON parsing collection of records


I've been struggling with this for long, I believe there's something wrong with my record design.

MY json looks like below. I posted this earlier as a part of another question but didn't get full answer especially for this part. Each record within the array is an object with a field name with data of type string.

JSON

[
    {
        "data": "/publication/a40a5e5c-98b3-45ae-d6a3-924b31d8712a/article/test;version=1521246543034"
    }, 
    {
        "data": "/publication/a40a5e5c-98b3-45ae-d6a3-924b31d8712a/book/test2;version=1520623346891"
    }, 
    {
        "data": "/publication/a40a5e5c-98b3-45ae-d6a3-924b31d8712a/catalog/test3;version=1520623346833"
    }
]

List.fs

open System.Runtime.Serialization

[<DataContract>]
type List= {
    [<field: DataMemberAttribute(Name="data") >]
    Data: string
}

Parsing JSON

let response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
use memoryStream = new MemoryStream(ASCIIEncoding.Default.GetBytes(reader.ReadToEnd())) 
let jsonSerializer = DataContractJsonSerializer(typeof<List[]>)
let result = jsonSerializer.ReadObject(memoryStream) :?> List[]
Debug.WriteLine(sprintf "%A" result)

Actual Output - having nulls

[|
    {Data = null;}; 
    {Data = null;}; 
    {Data = null;}
|]

Expected Output

[|
    {Data = "/publication/a40a5e5c-98b3-45ae-d6a3-924b31d8712a/article/test;version=1521246543034";}; 
    {Data = "/publication/a40a5e5c-98b3-45ae-d6a3-924b31d8712a/book/test2;version=1520623346891";}
    {Data = "/publication/a40a5e5c-98b3-45ae-d6a3-924b31d8712a/catalog/test3;version=1520623346833";}
|]

Iteration

result 
 > Array.iter (fun x -> Console.WriteLine(x.Href))

Solution

  • I suspect there must be something wrong with how you're reading the data. I tried to reproduce this and replaced the reading from a stream with reading from a string - so that I can test this - and the following works fine (in F# interactive version 14.0.23413.0):

    #r "System.Runtime.Serialization"
    open System.IO
    open System.Text
    open System.Runtime.Serialization
    open System.Runtime.Serialization.Json
    
    [<DataContract>]
    type List= {
        [<field: DataMemberAttribute(Name="data") >]
        Data: string
    }
    
    let reader = new StringReader("""[
        { "data": "/publication/a40a5e5c/article/test;version=1521246543034" }, 
        { "data": "/publication/a40a5e5c/book/test2;version=1520623346891" }, 
        { "data": "/publication/a40a5e5c/catalog/test3;version=1520623346833" } ]""")
    
    let memoryStream = new MemoryStream(ASCIIEncoding.Default.GetBytes(reader.ReadToEnd())) 
    let jsonSerializer = DataContractJsonSerializer(typeof<List[]>)
    let result = jsonSerializer.ReadObject(memoryStream) :?> List[]
    result
    

    Can you check that your input JSON is actually the one you shared here? To do that, see what reader.ReadToEnd() returns before calling GetBytes - I suspect there must be something wrong there, because the rest of the code works fine for me.