DEV Community

Rob Mulpeter
Rob Mulpeter

Posted on

XmL Serialization for F# Record Types

While Microsoft do provide documentation for XmlSerializer the examples are currently in C# only. Equally, many long-standing and valid community solutions can only be found when using keywords which indicate you already know the answer! Quite annoying.

The purpose of this article is to provide you with a clear working example of serializing an F# record type using the XmlSerializer class and CLIMutable attribute.

XmlSerializer ๐Ÿฅฃ

The caveat of using the XmlSerializer with F# is that the class requires the referenced type to have a parameterless constructor in order to work. Such constructors are implicitly created in the background for C# classes without any explicit constructors defined. This is not the case for an F# record type.

The below example implements a simple type with some elements, attributes and an array of sub-types.

Record Type

[<CLIMutable>]
[<XmlRoot("Student")>] 
type Student =
  { [<XmlAttribute("id")>]
    Id : int
    [<XmlElement("Name")>]
    Name : string }

[<CLIMutable>]
[<XmlRoot("Master")>] 
type Master = 
  { [<XmlAttribute("id")>]
    Id : int
    [<XmlElement("Name")>]
    Name : string
    Students : Student [] }
Enter fullscreen mode Exit fullscreen mode

The below implementation of the serialization logic is standard, with a new StringWriter, the payload and some namespace configuration being passed to the Serialize function of XmlSerilizer.

Serializer

let payload : Master =
    {
        Id = 1984
        Name = "Johnny Lawrence"
        Students = [|
            { Id = 1; Name = "Miguel Diaz" }
            { Id = 2; Name = "Hawk" }
        |]
    }            

let serializerNamespaces = XmlSerializerNamespaces()
serializerNamespaces.Add("", "")

let writer = new StringWriter()

let serializer = XmlSerializer(typeof<Master>)
serializer.Serialize(writer, payload, serializerNamespaces)

printf $"{writer.ToString()}"
Enter fullscreen mode Exit fullscreen mode

Output

<?xml version="1.0" encoding="utf-16"?>
<Master id="1984">
  <Name>Johnny Lawrence</Name>
  <Students>
    <Student id="1">
      <Name>Miguel Diaz</Name>
    </Student>
    <Student id="2">
      <Name>Hawk</Name>
    </Student>
  </Students>
</Master>
Enter fullscreen mode Exit fullscreen mode

Mutable ๐ŸงŸโ€

The reason the above serialization works is because we added the [<CLIMutable>] attribute to each of the types to be serialized. The attribute instructs the compiler to add internal auto-generated mutable fields. From a programming perspective, the type is still immutable as these internal fields can only be accessed by automated processes or if you decided to expose the type to C# code.

By using this attribute we can make use of normal .NET serializers and avoid harder to work with solutions like the DataContractSerializer.

Working Example ๐Ÿงช

The following solution provides an example of the XmlSerializer turning a record type into an xml formatted string for an API response. This solution is an open-source implementation of asynchronous, long-running tests in Orleans which produce TRX results via a HTTP web API endpoint.

Co-Author: Piotr Justyna

Oldest comments (0)