Why are Pages and Blocks Returned From The Episerver API Read-Only?

When you use the Get<>() or GetChildren<>() methods from IContentLoader or IContentRepository, the page data that will get returned will always be a read-only version. If you try and update a property and save it you will get

Why?

Why would Episerver make everything read-only? One reason is to simplify the API for everyone. In 95% of the situations when you will be working with pages or blocks, you will only need to access them in a read-only context, like displaying data on the screen. By making all the objects returned from the API immutable (read-only) when you work with an object, you know that it won’t change.

This allows the API to share the same object instance between several different threads. This type of architecture significantly reduces the amount of short-lived objects being created and consequently reduce the amount of memory that your website will use.

IReadOnly

The interface Read-only handling has been added for the EPiServer.Core.PageData class and all contained classes.

Behind the scenes when you call Get<>() or GetChildren<>() Episerver first creates a writable PageData object. The object is then populated with it’s corresponding data. A call is made to IReadOnly.MakeReadOnly(), which in turn makes the page/blocks properties immutable. The object is added to the cache and any subsequent calls from that page or block from the API will return that object.

How Do I Update A Page?

If you try and load a page from the API and save it directly you will receive a System.NotSupportedException telling you that the ‘The property **** is read-only.’

When you work with pages and blocks you may notice the CreateWritableClone() method. This as the name suggests makes a mutable copy of the page. With this new writable copy, you can update as you want.

var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
var contentReference = new ContentReference(5);
var variant = contentRepository.Get<ContentPage>(contentReference);
var clone = variant.CreateWritableClone<ContentPage>();
clone.name = "Update";
contentRepository.Save(clone,SaveAction.Publish, AccessLevel.NoAccess);

In the code above, we use IContentRepository instead of IContentLocator as it gives us access to the Save method. We retrieve the page/block from the database using the IContentRepository.Get<>() method, which returns an immutable copy of the page/block.

To make the object writable, we create a clone/copy of it using the CreateWritableClone() method defined on the IReadOnly interface that every block and page has to inherit from. When we have a copy of the clone, you can update it as how you want. You can then use the IContentRepository.Save() to persist the data back to the database.

If you need to know if the page/block you are currently working with is read-only or a clone you can use the IsReadOnly property.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

2 replies

Trackbacks & Pingbacks

  1. […] More information about what an Episerver page or block is can be found in this Episerver CMS tutorial, What Is The Difference Between An Episerver Page and an Episerver Block? […]

  2. […] object cache is built on top of the ASP.NET runtime cache. As mentioned in Why are Pages and Blocks Returned From The EpiServer API Read-Only?. Th API only returns read-only objects for better performance. This mechanism enhances scalability, […]

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *