Support for Block as Property in the Episerver Content Delivery API

Since Episerver 7, CMS has support to add Blocks as Properties. This helps you to group Properties easier as well as reusing code.

Unfortunately the Episerver Content Delivery API does not support these blocks. They are simply not serialized into the JSON response.

In my example I will use the StartPage from the Alloy Templates that has the Block SiteLogotypeBlock added as a Property:

public virtual SiteLogotypeBlock SiteLogotype { get; set; }

When I use the Content Delivery API to request the Start Page, I don’t see it in the JSON response.

no logo

The structure of Block as Property

Without digging too deep into how Episerver structure the Blocks when they are added as properties, you can find that the PropertyData for the SiteLogotypeBlock is defined as BlockProperty.

Normally I would simply need to create a PropertyModel that handles BlockProperty and handles the Block property values similar to how I add PropertyModels with complex value models.

But I don’t want to do that for every Block Type that might be added as a Block!

Extending with a PropertyModelConverter

Fortunately, all BlockProperty inherit from BlockProperty!

This makes it easier for me to create my own PropertyModelConverter (the part responsible of finding a PropertyModel for the PropertyData) and check if the current PropertyData is assignable from BlockProperty.

Default:

propertyModel.PropertyType == propertyData.GetType()

Which does not consider heritance.

My implementation:

propertyData is PropertyBlock;

With this, I can take any BlockProperty into my own PropertyModel.

The BlockPropertyModel

What I did was to create a PropertyModel that is using the ContentModelMapper to serialize the Block. This is the same function that is used to make the requested Content into a serializable model.

Unfortunately the ContentModelMapper can only handle IContent. PageData implements IContent and so does Blocks that are created in the Assets Pane due to Episerver’s runtime proxy.

However Blocks that are added as Properties does not implement IContent.

Dirty workaround ;)

So how can I ask the ContentModelMapper to map my non-IContent Block? This is not the best solution I’ve found but I ask the IContentRepository to create a Default instance of the Block Type in the same way as if I would create a block programmatically.

var fakeContent = this.contentRepository.GetDefault(ContentReference.SiteBlockFolder, contentTypeId);

After that I copy all of the property values from the original Block into my fake instance.

var propertyDataCollection = block.Property.CreateWritableClone();
foreach (var propertyData in propertyDataCollection)
{
    fakeContent.Property.Set(propertyData.Name, propertyData);
}

And finally I ask the ContentModelMapper to map this into a ContentModel.

this.contentModelMapper.TransformContent((IContent)fakeContent);

After cleaning upp things that I don’t really need like Name, ParentLink etc. I can use this as the Value of the PropertyModel.

Summary

To be able to accomplish this, I needed to be able to find a way to handle all different types of PropertyBlocks and be able to serialize the actual Block Types.

Using the BlockPropertyModelConverter I am able to map the BlockProperty of any type into my BlockPropertyModel, which in turn use BlockModelMapper to create a serializable model using the normal ContentModelMapper.

Now I will get any Block that is added as a Property serialized as JSON into the Content Delivery API Response!

logo

If you want to understand more about the Episerver Content Delivery API serializing, you can read it in the documentation.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: