Handle Yaml Files with .NET

BEN ABT
medialesson
Published in
4 min readApr 23, 2024

YAML files are unfortunately part of everyday life for all developers these days; and although they are very error-prone and almost impossible to edit without an IDE and schema information without constantly running into errors — many greetings to all CI systems that think this was a good idea: it wasn’t — we have to accept that we have to process them.

In .NET, the YamlDotNet library is a popular choice for processing YAML files. This library is very easy to use and provides very good support for most YAML files.

When processing YAML files, YamlDotNet offers two different options: key-value access via a dictionary, or deserialization into a class. Both methods have their advantages and disadvantages, but in most cases deserialization into a class is the more convenient and better choice.

Deserialize from YAML

For a deserialization into a class, corresponding classes are also necessary; as an example I take a structure of a potential header of a blog post:

title: Handle Yaml Files with .NET
description: This blog post shows a simple sample how to serialize and deserialize yaml files with .NET

options:
isDraft: true
date: 2024-04-23T15:30:00Z
author:
name: BEN ABT
twitter: https://twitter.com/Abt_Benjamin
linkedIn: https://www.linkedin.com/in/benjaminabt/
job:
company: Medialesson GmbH
description: Chief PullRequest Officer
website: https://media-lesson.com/

Accordingly, the class structure can be implemented 1:1:

public class BlogPost
{
public string Title { get; set; } = null!;
public string Description { get; set; } = null!;
public Options Options { get; set; } = null!;
public Author Author { get; set; } = null!;
public string Content { get; set; } = null!;
}
public class Options
{
public bool IsDraft { get; set; }
public DateTimeOffset Date { get; set; }
}
public class Author
{
public string Name { get; set; } = null!;
public string Twitter { get; set; } = null!;
public string LinkedIn { get; set; } = null!;
public Job Job { get; set; } = null!;
}
public class Job
{
public string Company { get; set; } = null!;
public string Description { get; set; } = null!;
public string Website { get; set; } = null!;
}

As of today, no records are supported in YamlDotNet; the deserializer needs a class with an empty constructor and the corresponding setters in the properties.

Deserialization is then very simple:

IDeserializer deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();

// yamlBlogPost = string with yaml content
BlogPost blogPost = deserializer.Deserialize<BlogPost>(yamlBlogPost);

The blogPost object then contains the corresponding values from the YAML file as an instance, which can be accessed as usual.

Serialize to YAML

Serialization is just as easy — only in reverse:

ISerializer serializer = new SerializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();

string blogPostYaml = serializer.Serialize(blogPost);

The complete sample

// --------------------------------------------------------------------
// This sample shows the handling of YAML files in .NET.
// The YamlDotNet library (https://github.com/aaubry/YamlDotNet) is used to serialize and deserialize YAML files.
// 2024-04-23 - https://schwabencode.com

// Runtime: .NET 8
// Sample Project: Console App
// Dependency: YamlDotNet

using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

// --------------------------------------------------------------------
// sample Yaml-File in style of a blog post header
string yamlBlogPost =
"""
title: Handle Yaml Files with .NET
description: This blog post shows a simple sample how to serialize and deserialize yaml files with .NET

options:
isDraft: true
date: 2024-04-23T15:30:00Z
author:
name: BEN ABT
twitter: https://twitter.com/Abt_Benjamin
linkedIn: https://www.linkedin.com/in/benjaminabt/
job:
company: Medialesson GmbH
description: Chief PullRequest Officer
website: https://media-lesson.com/
""";

// --------------------------------------------------------------------
// deserialize string as model
IDeserializer deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();

BlogPost blogPost = deserializer.Deserialize<BlogPost>(yamlBlogPost);

// Print blog post
Console.WriteLine(new string('-', 30));
Console.WriteLine($"## Print Blog Post Object");
Console.WriteLine($"Title: {blogPost.Title}");
Console.WriteLine($"\tDescription: {blogPost.Description}");
Console.WriteLine($"Options");
Console.WriteLine($"\tIs Draft: {blogPost.Options.IsDraft}");
Console.WriteLine($"\tDate: {blogPost.Options.Date:o}");
Console.WriteLine($"Author");
Console.WriteLine($"\tName: {blogPost.Author.Name}");
Console.WriteLine($"\tTwitter: {blogPost.Author.Twitter}");
Console.WriteLine($"\tLinkedIn: {blogPost.Author.LinkedIn}");
Console.WriteLine($"\tJob");
Console.WriteLine($"\t\tCompany: {blogPost.Author.Job.Company}");
Console.WriteLine($"\t\tDescription: {blogPost.Author.Job.Description}");
Console.WriteLine($"\t\tWebsite: {blogPost.Author.Job.Website}");

// --------------------------------------------------------------------
// create yaml serializer with options
ISerializer serializer = new SerializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();

string blogPostYaml = serializer.Serialize(blogPost);

Console.WriteLine(new string('-', 30));
Console.WriteLine($"## Print Blog Post Text");
Console.WriteLine(blogPostYaml);

// --------------------------------------------------------------------
// sample models as classes, records are not supported today
public class BlogPost
{
public string Title { get; set; } = null!;
public string Description { get; set; } = null!;
public Options Options { get; set; } = null!;
public Author Author { get; set; } = null!;
public string Content { get; set; } = null!;
}
public class Options
{
public bool IsDraft { get; set; }
public DateTimeOffset Date { get; set; }
}
public class Author
{
public string Name { get; set; } = null!;
public string Twitter { get; set; } = null!;
public string LinkedIn { get; set; } = null!;
public Job Job { get; set; } = null!;
}
public class Job
{
public string Company { get; set; } = null!;
public string Description { get; set; } = null!;
public string Website { get; set; } = null!;
}

PS: please do not use Yaml, if you don’t have to. Everyone hates yaml. Thanks.

Autor

Benjamin Abt

Ben is a passionate developer and software architect and especially focused on .NET, cloud and IoT. In his professional he works on high-scalable platforms for IoT and Industry 4.0 focused on the next generation of connected industry based on Azure and .NET. He runs the largest german-speaking C# forum myCSharp.de, is the founder of the Azure UserGroup Stuttgart, a co-organizer of the AzureSaturday, runs his blog, participates in open source projects, speaks at various conferences and user groups and also has a bit free time. He is a Microsoft MVP since 2015 for .NET and Azure.

Originally published at https://schwabencode.com on April 23, 2024.

--

--