XmL Serialization for F# Record Types
Tags: beginners, fsharp, programming, dotnet
Published: 2022-02-22 18:46:56

While Microsoft do provide [documentation](https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer?view=net-6.0) 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**
```c#
[<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 [] }
```

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**
```c#
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()}"
```
**Output**
```xml
<?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>
```

## 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](https://github.com/PiotrJustyna/Palladium/blob/main/SiloHost/src/Controllers/AsynchronousTestsController.fs) 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](https://github.com/PiotrJustyna)