Serializing custom annotations in .NET
Set up a serializer for rendering custom annotations using Sanity LINQ in .NET
Go to Serializing custom annotations in .NETSanity.io is a headless CMS. Since a headless CMS acts as an API for our raw data, it makes it easy to distribute the data to multiple channels such as mobile, web and wearables.
A way for Sanity to distribute text across all channels is by using Portable Text. The text editor comes with a decent amount of functionality by default, but we might want to add more complex objects in our text and render these objects in our front end.
In this guide, we will create and add an object category to the Portable Text toolbar. We will then create a custom serializer to build an HTML string in a .NET web application.
First, we will create an object called category.
// category.js
export default {
name: 'category',
title: 'Category',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'description',
title: 'Description',
type: 'text'
}
]
}
To add this to our existing Portable Text component, put the new types after the block type in the array.
//blockContent.js
export default {
title: 'Block Content',
name: 'blockContent',
type: 'array',
of: [
{
title: 'Block',
type: 'block',
styles: [
{title: 'Normal', value: 'normal'},
{title: 'H1', value: 'h1'},
{title: 'H2', value: 'h2'},
{title: 'Quote', value: 'blockquote'},
],
lists: [{title: 'Bullet', value: 'bullet'}],
marks: {
decorators: [
{ "title": "Strong", "value": "strong" },
{ "title": "Emphasis", "value": "em" },
{ "title": "Code", "value": "code" },
]
}
},
//Adding our custom object type to the portable text toolbar
{
title: 'Category',
type: 'category'
}
]
}
Inside Sanity's Portable Text editor we now have an option to insert a category object.
After publishing our page, we can inspect the data for our current page. The data retrieved from our rich text comes as an array. "This is a normal text" is at position 0, and our category object comes as position 1. As we can see, the plain text has a _type: block while our custom object has a _type: category.
We can now use Sanity LINQ to fetch data from our Sanity Studio. Sanity LINQ also comes with an HTML builder that can parse the portable text and return an HTML string.
//Fetching our post from Sanity using Sanity.Linq
post = await SanityService.SanityDataContext.DocumentSet<Post>()
.Where(p => p.Slug.Current == current)
.FirstOrDefaultAsync();
if (post?.Body?.Any() == true)
{
// Build HTML using Sanity.Linq html builder
post.HtmlBody = await SanityService.SanityDataContext.HtmlBuilder.BuildAsync(post.Body);
}
// Rendering our HTML string in Blazor
@if (!string.IsNullOrWhiteSpace(current) && post != null)
{
<p>
@((MarkupString)post.HtmlBody)
</p>
}
If we try to open our page now, we get an error:
Error: System.Exception: No serializer for type 'category' could be found. Consider providing a custom serializer or setting HtmlBuilderOptions.IgnoreAllUnknownTypes.
To fix this we need to create a serializer that we can pass to the HTML builder.
When adding a serializer we need to supply the type of object the serializer should expect. In this case, it is category. The second parameter is a delegate Func<JToken, SanityOptions, Task> serializer.
//Creating a simple method for serializing.
public Task<string> SerializeCategoryBlock(JToken input, SanityOptions sanity)
{
return Task.FromResult("Hello from custom serializer!");
}
public SanityService()
{
_sanityOptions = new SanityOptions
{
ProjectId = "<project id>",
Dataset = "<dataset>",
Token = "<token>",
UseCdn = false
};
SanityDataContext = new SanityDataContext(_sanityOptions);
//Adding our serializer
SanityDataContext.AddHtmlSerializer("category", SerializeCategoryBlock);
}
Refreshing the page, we can now see our newly rendered category object.
So this is nice and all, but we need to get the information we want from our object for this to be useful.
If we look inside Sanity Studio and inspect our body object we can see the category type. This is the data we get inside our JToken in the serializer.
So for this particular object, it is fairly easy to get the data we need.
public Task<string> SerializeCategoryBlock(JToken input, SanityOptions sanity)
{
var title = input["title"].ToString();
var description = input["description"]?.ToString();
return Task.FromResult($"<h2>{title}</h2><p>{description}</p>");
}
And there we have it! Our custom object is now rendered in HTML using Sanity LINQ's HTML builder.
Sanity Composable Content Cloud is the headless CMS that gives you (and your team) a content backend to drive websites and applications with modern tooling. It offers a real-time editing environment for content creators that’s easy to configure but designed to be customized with JavaScript and React when needed. With the hosted document store, you query content freely and easily integrate with any framework or data source to distribute and enrich content.
Sanity scales from weekend projects to enterprise needs and is used by companies like Puma, AT&T, Burger King, Tata, and Figma.
Set up a serializer for rendering custom annotations using Sanity LINQ in .NET
Go to Serializing custom annotations in .NET