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 [] }
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()}"
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>
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
Top comments (0)