Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more

Johan Björnfot
Nov 30, 2012
  15150
(0 votes)

Shared blocks – IContent

Blocks is a new building block introduced in EPiServer CMS 7. A block can be used in several ways, it can be used as a “complex” property when modeling content types. It is also possible to create stand alone instances of blocks (shared blocks) that can be reused on content areas on other content  instances. Joel have written an good post about how to work with block properties (see http://joelabrahamsson.com/entry/working-programmatically-with-local-blocks-in-episerver-7 ). In this post I am going to explain a bit about how to work programmatically with shared block instances.

IContent

In previous versions of CMS was pages (PageData) the only content type that the content repository (traditionally DataFactory) handled. In CMS7 this has changed so now content repository (IContentRepository) handles IContent instances. This means that the requirement for a .NET type to be possible to save/load from content repository is that it implements the interface EPiServer.Core.IContent.

There are some implementations of IContent built into CMS like PageData and ContentFolder (used to group shared block instances) and it is also possible to register custom IContent implementations.

If you look at BlockData though you will notice that it doesn’t implement IContent, how is then shared block instances handled? The answer is that during runtime when a shared block instance is created (e.g. through a call to IContentRepository.GetDefault<T> where T is a type inheriting from BlockData) the CMS will create a new .NET type inheriting T using a technic called mixin where the new generated subclass will implement some extra interfaces (including IContent).

That means that a shared block instance of T will implement IContent while an instance of T that is a property on a Page will not. If you attach a debugger and look at the instance returned from GetDefault<T> (where T is a type inheriting BlockData) you can see that the instance looks like:

SharedBlock

Here we can see that the shared block instance have some extra fields for each interface that is mixed in.

So when working with shared blocks towards IContentRepository you can cast instance to IContent like below:
var repository = Locate.ContentRepository();

var sharedBlock = repository.GetDefault<ButtonBlock>(ContentReference.GlobalBlockFolder);
sharedBlock.ButtonLink = new Url("http://world.episerver.com");
sharedBlock.ButtonText = "world";

//Since this is a shared block instance I can cast it to IContent
var content = sharedBlock as IContent;
content.Name = "MyButton";
var savedReference = repository.Save(content, DataAccess.SaveAction.Publish);

//I do not need to load it as ButtonBlock, here I load it as IContent
var loaded = repository.Get<IContent>(savedReference);
Debug.Assert(loaded.Name == content.Name);

Behavioral interfaces

As described above IContent is a required interface for content. In addition to IContent there are a number of behavioral interface that is optional for a content type to implement depending on if that behavior should be supported. Below is a list of the behavioral interfaces with a short description on what they contain/support:

IVersionable

Implement to supports versioning.

ILocalizable

Implement to support multi language.

ICategorizable

Implement to support categorizing.

ISecurable

Implement to support readonly access checks.

IContentSecurable

Implement to support access checks that is also possible to modify through IContentSecurityRepository.

IChangeTrackable

Implement to support change tracking.

IModifiedTrackable

Implement to support modified tracking.

IReadOnly/IReadOnly<T>

Implement  to ensure cached instances are immutable.

IResourceble

Implement to state that instance supports content folder.

IExportable

Implement to control if the instance should implicitly be added to export package when referenced (e.g. from ContentArea).

IRoutable

Implement if is should be possible to route to instance (without partial router).

Suggested patterns

The suggested pattern when working with metadata on content is to cast the instance to the corresponding interface with as operator and then act depending on if the interface is implemented or not like in example below:

private string GetRoutingSegment(IContent content)
{
   IRoutable routable = content as IRoutable;
   return routable != null ? routable.RouteSegment : null;
}
And since types are dynamically subclassed you should not use exact type match as below to check a type
if (typeof(ButtonBlock) == content.GetType())

instead you can use operators is, as or method IsAssignableFrom like:

if (content is ButtonBlock) {/*code*/ }

var buttonBlock = content as ButtonBlock;
if (buttonBlock != null)
{ /*code*/ }

if (typeof(ButtonBlock).IsAssignableFrom(content.GetType()))
{ /*code*/ }
Nov 30, 2012

Comments

Please login to comment.
Latest blogs
Optimizely Configured Commerce and Spire CMS - Figuring out Handlers

I recently entered the world of Optimizely Configured Commerce and Spire CMS. Intriguing, interesting and challenging at the same time, especially...

Ritu Madan | Mar 12, 2025

Another console app for calling the Optimizely CMS REST API

Introducing a Spectre.Console.Cli app for exploring an Optimizely SaaS CMS instance and to source code control definitions.

Johan Kronberg | Mar 11, 2025 |

Extending UrlResolver to Generate Lowercase Links in Optimizely CMS 12

When working with Optimizely CMS 12, URL consistency is crucial for SEO and usability. By default, Optimizely does not enforce lowercase URLs, whic...

Santiago Morla | Mar 7, 2025 |

Optimizing Experiences with Optimizely: Custom Audience Criteria for Mobile Visitors

In today’s mobile-first world, delivering personalized experiences to visitors using mobile devices is crucial for maximizing engagement and...

Nenad Nicevski | Mar 5, 2025 |

Unable to view Optimizely Forms submissions when some values are too long

I discovered a form where the form submissions could not be viewed in the Optimizely UI, only downloaded. Learn how to fix the issue.

Tomas Hensrud Gulla | Mar 4, 2025 |

CMS 12 DXP Migrations - Time Zones

When it comes to migrating a project from CMS 11 and .NET Framework on the DXP to CMS 12 and .NET Core one thing you need to be aware of is the...

Scott Reed | Mar 4, 2025