I love using F#’s Record and Dis­crim­i­nated Union types, they work nicely with pat­tern match­ing inside your F# code and can often alle­vi­ate some of the cer­e­mony involved around cre­at­ing and using a com­plex object hierarchy.

How­ever, on the odd occa­sion when you need to seri­al­ize them into JSON/XML/Binary for­mat, it might not be imme­di­ately obvi­ous what you need to do to achieve that goal.

In gen­eral, I avoid using F# spe­cific types when I require inter­op­er­abil­ity with C# and/or sup­port for trans­port as it’s just much more eas­ily done with stan­dard CLR types. How­ever, in case that’s not an option, I hope this post will give you a sum­mary of the dif­fer­ent ways you can pre­pare your Record/DU types for transport.

Record

To seri­al­ize a Record type using the Dat­a­Con­tract­Se­ri­al­izer (for XML) or Dat­a­Con­trac­tJ­son­Se­ri­al­izer (for JSON), sim­ply dec­o­rate your Record type with Dat­a­Con­trac­tAt­tribute and DataMem­ber­At­tribute like you nor­mally would:

image

After that you can serialize/deserialize a Per­son instance nor­mally although the seri­al­ized XML/JSON would not be as read­able as with other CLR types:

JSON

Record:

{“Age@”:99,“Name@”:“Yan Cui”}

Class:

{ “Age” : 99, “Name” : “Yan Cui” }

XML

Record:

<FSI_0002.Person xmlns=”http://schemas.datacontract.org/2004/07/”

                            xmlns:i=“‘http://www.w3.org/2001/XMLSchema-instance”>

    <Age_x0040_>99</Age_x0040_>

    <Name_x0040_>Yan Cui</Name_x0040_>

</FSI_0002.Person>

Class:

<Per­son xmlns=”http://schemas.datacontract.org/2004/07/ClassLibrary1”

             xmlns:i=“http://www.w3.org/2001/XMLSchema-instance”>

    <Age>99</Age>

    <Name>Yan Cui</Name>

</Person>

As for binary seri­al­iza­tion, a Record type is marked with the Seri­al­iz­able attribute by default, which means it can be seri­al­ized with the Bina­ry­For­mat­ter. This is how the Per­son record type looks in reflector:

image

Dis­crim­i­nated Unions

A sin­gle case Dis­crim­i­nated Union such as the one below is seri­al­iz­able by Dat­a­Con­tract­Se­ri­al­izer, Dat­a­Con­trac­tJ­son­Se­ri­al­izer and Bina­ry­For­m­mat­ter out of the box.

image

The JSON and XML out­put for an instance of this DU looks like this:

JSON :

{“item”:“test”}

XML   :

<Sin­gle­CaseDU xmlns=”http://schemas.datacontract.org/2004/07/”

                        xmlns:i=“http://www.w3.org/2001/XMLSchema-instance”>

    <item>test</item>

</SingleCaseDU>

A multi-case Dis­crim­i­nated Union on the other hand, requires a lit­tle more work.

image

Whilst it works with Bina­ry­For­mat­ter by default, it will not with Dat­a­Con­tract­Se­ri­al­izer and Dat­a­Con­trac­tJ­son­Se­ri­al­izer. If you try to seri­al­ize an instance of Mul­ti­Cas­eDU using either you will get a Seri­al­iza­tionEx­cep­tion say­ing that the type MultiCaseDU.Case1 or MultiCaseDU.Case2 is not expected.

So to make the Mul­ti­Cas­eDU type seri­al­iz­able with both Dat­a­Con­tract­Se­ri­al­izer and Dat­a­Con­trac­tJ­son­Se­ri­al­izer you need to sup­ply the nested types (Case1 and Case2) to the known type resolver. Some­thing like this would do the trick:

image

After that, you’ll be able to seri­al­ize instances of Mul­ti­Cas­eDU:

JSON

Case1:

{“__type”:“MultiCaseDU.Case1:#FSI_0002.Contracts”,“item”:“test”}

Case2:

{“__type”:“MultiCaseDU._Case2:#FSI_0002.Contracts”}

XML

Case1:

<Mul­ti­Cas­eDU i:type=“MultiCaseDU.Case1”

                     xmlns=”http://schemas.datacontract.org/2004/07/”

                     xmlns:i=“http://www.w3.org/2001/XMLSchema-instance”>

    <item>test</item>

</MultiCaseDU>

Case2:

<Mul­ti­Cas­eDU i:type=“MultiCaseDU._Case2”

                     xmlns=”http://schemas.datacontract.org/2004/07/”

                     xmlns:i=“http://www.w3.org/2001/XMLSchema-instance”/>

 

 

 

For the full exam­ple, includ­ing seri­al­iza­tion and dese­ri­al­iza­tion code, see this gist.

Share

One Response to “F# – Serializing F# Record and Discriminated Union types”

  1. […] talked about the XML and JSON seri­al­iza­tion of F# types in a pre­vi­ous post, and since then F# 3.0 has been released and a new [CLIMutable] was qui­etly added amidst the hype […]

Leave a Reply