Try our conversational search powered by Generative AI!

Loading...
Area: Optimizely CMS
ARCHIVED This content is retired and no longer maintained. See the latest version here.

Recommended reading 

Introduction

This document provides an introduction to rendering of content such as pages and blocks in EPiServer CMS. Content is rendered using display templates as described below.

Rendering of pages

A template is responsible for rendering a page type. In EPiServer CMS a template defines which page types it can render, not the other way around, which gives a clean separation of model and presentation and allows for easier extensibility. Several templates (both Web Form and MVC ) can be registered for any content type (typically pages or blocks even if the underlying templating system supports any .NET type).

The template chosen to render a content instance depends on the specific context such as channel and tagging. For a template to be automatically registered it has to implement EPiServer.Web.IRenderTemplate<T> (where T states which model it can render). If you use a base class for your template like PageBase<T>, ContentControlBase<T>, BlockControlBase<T>, PageController<T>, PartialContentController<T> or BlockController<T>, then you do not need to explicitly implement the interface since that is done by the base class. In addition the TemplateDescriptorAttribute can be used to specify more details about the template such as tags and inheritance, more information on that topic later.

A model is defined as shown in the following example:

[ContentType]
public class MyPage : PageData
{
    public virtual string Heading { get; set; }
    public virtual string MainIntro { get; set; }
    public virtual XhtmlString MainBody { get; set; }
}

Given that there are templates defined as follows:

public partial class MyPageTemplate : TemplatePage<MyPage> { }

[TemplateDescriptor(Tags = new string[] { RenderingTags.Mobile })]
public partial class MyPageMobileTemplate : TemplatePage<MyPage> { }

[TemplateDescriptor(Inherited = true)]
public partial class MyFallbackTemplate : TemplatePage<PageData> { }

public partial class MyPageTeaser : ContentControlBase<MyPage> { }

[TemplateDescriptor(Inherited = true)]
public partial class PageTeaser : ContentControlBase<PageData> { }

All of the above templates will be registered as templates for MyPage, which one that actually gets selected is dependent on the context as mentioned earlier.

It is possible to register a template for both a base type and an interface (see MyFallbackTemplate and PageTeaser above which are registered for PageData, not the specific type). In the case you want the template to be available for all subtypes as well, you need to mark it with Inherited=true on the TemplateDescriptor attribute. This can be useful, for example, if you want to have a fallback template for content types that still not have a specific template.

The algorithm to select a template is handled by TemplateResolver and the default implementation in the following way:

  1. First event EPiServer.Web.TemplateResolver.TemplateResolving is raised, if an event handler selects a template that template is used with no further handling.
  2. Else all the templates matching a type is filtered according to if the rendering mode is a page (in that case suitable templates are Web Form or MVC controller) or a partial rendering (in that case a suitable template is a WebControl, UserControl, MVC partial controller or a MVC partial view). For partial templates the list is filtered according to main template, that is if the main request is a handled by, for example, a Web Form then only partial web form renderers are taken into account and the same applies if main template is an MVC Controller then only partial MVC templates are taken into account.
  3. If the template is requested with a specific tag the list is filtered on that tag (for example, rendering of a ContentArea can be tagged with “SideBar” and then templates with matching tag is preferred).
  4. If no template matched tag continue with all templates from point 2.
  5. If any DisplayChannel is active and there are templates with a Tag matching the active channel the templates are filtered to the ones matching the DisplayChannel.
  6. From the remaining templates select the “closest” TemplateModel that is marked as Default (can be set on TemplateDescriptor attribute) and not inherited.
  7. If no match from 5 select “closest” TemplateModel that is marked as Default.
  8. If no match from 6 select “closest” TemplateModel.
  9. Event EPiServer.Web.TemplateResolver.TemplateResolved is raised, giving chance to replace selected template.

With “closest” above means the template model with shortest “inheritance chain”. That means that a template that is registered direct for the model will be preferred before a template registered for a base class or interface. For interfaces the length of the “inheritance chain” is defined by walking the inheritance chain upwards and see where the interface is implemented.

There is also possible in admin mode (on PageType/BlockType) to “override” which template that should be used by default. In that case the check for “closest” template will be skipped and instead that template model will be used.

So in the example above a request in a “ordinary web browser” for a page of type MyPage (assuming no DisplayChannel is active) the template MyPageTemplate will be selected since then no tag is active (disqualifies MyPageMobileTemplate) and MyPageTemplate has shorter inheritance chain than MyFallbackTemplate (MyPageTeaser and PageTeaser is partial renderers and will be filtered away when selecting a page renderer).

And in case there is a DisplayChannel named “Mobile” active for a request, for example, an implementation that check if request is from a mobile device, then the template MyPageMobileTemplate will be selected, since when selecting templates we will prefer templates that have a tag matching active channels.

Rendering of blocks

The selection of a template for a block is similar to the selection for a page with the difference that since a block is rendered in the context of a parent page (either it is a property on a typed page or a shared block instance rendered in a content area) the selection of the block template is done in context of the page template. This means you can have both a User Control and a MVC Controller (for example, a partial view or a partial controller) then depending on if the block is rendered in the context of a Web Form page or a MVC page the suitable template will be selected automatically.

When rendering a ContentArea or a block property on a page you can also specify a tag to have specific templates for some areas on the site as follows:

<EPiServer:Property runat="server" PropertyName="MyContentArea">
    <RenderSettings Tag="SideBar" />
</EPiServer:Property>
<%: Html.PropertyFor(m => m.MyBlockProperty, new { Tag = RenderingTags.Sidebar })%>
<%: Html.PropertyFor(m => m.MyContentArea, new { Tag = RenderingTags.Sidebar })%>

Block layout in a content area

If a tag is specified on a content area then content added to that area will use the template matching that tag; or it will display a message informing the user that no renderer exists for the combination of content type and tag. If a content within the content area has been configured to have a specific tag via the display options then that tag will be used instead of the content area's tag when resolving the template for the content.

Previewing block in on-page editing

Normally a block is displayed in the context of a page (for example, rendered inside a ContentArea). Therefore a block template is typically a partial template like a UserControl or Partial MVC controller/Partial View. However when a shared block instance is edited then we need to render the shared block instance with a page renderer. So for editing purposes it is useful to register a page renderer that can be used when editing shared block instances, for that purpose a reserved tag “Preview” is used.

 A Web Form template is shown in the following example:

[TemplateDescriptor(Inherited=true, Tags= new string[]{RenderingTags.Preview})]
public partial class PreviewBlock : SimplePage, IRenderTemplate

A MVC page controller for editing of shared block could be defined as shown in the following example:

[TemplateDescriptor(Inherited = true, Tags = new string[] { RenderingTags.Preview })]
public class PreviewBlockController : ActionControllerBase, IRenderTemplate

IViewTemplateModelRegistrator

As mentioned before instances implementing EPiServer.Web.IRenderTemplate will be automatically registered. The same goes for partial views that follows the “standard” ASP.NET MVC conventions, for example, if there is a block type as follows:
[ContentType]
public class TeaserBlock : BlockData
{
    public virtual string Heading { get; set; }
    public virtual XhtmlString MainIntro { get; set; }
}

If there is a partial view in /View/Shared/TeaserBlock.cshtml that has a model set to TeaserBlock, that partial view will also be automatically registered. However since it is not possible to set TemplateDescriptor attribute on a partial view it is also possible to implement EPiServer.Web.Mvc.IViewTemplateModelRegistrator to register a partial view. A registration of a partial view through that interface is shown in the following example:

viewTemplateModelRegistrator.Add(typeof(TeaserBlock),
               new DataAbstraction.TemplateModel()
               {
                   Name = "SidebarTeaser",
                   Description = "Displays a teaser of a page.",
                   Path = "~/Views/Shared/SidebarTeaserBlock.cshtml",
                   Tags = new string[]{RenderingTags.Sidebar}
               }
           );

Path resolving

For Web Forms and User Controls the virtual path to the aspx or ascx has to be known to be able to load the page/user control. There is a possibility to specify the path on the TemplateDescriptor attribute. If the path is not specified then we will try to resolve the path according to the namespace. That means that if your folder structure follows the namespace then it is not required to explicitly specify the path.

Display channels

Display channels can be used to select templates based on context, allowing the editor to switch channels when previewing content. A display channel is a class that for each request is matched to see if it is considered active or not (similar to a visitor groups). There is a similar concept called Display Mode introduced in MVC 4, you can use display modes in MVC 4 to create templates for display channels which is very powerful integration. Whenever a display channel is active templates with a tag that matches the channel will be preferred. For example, if there is a display channel implementation that returns true for mobile devices (named Mobile) and then whenever that channel is active templates with tag Mobile will be preferred. That means you can choose to have duplicate templates for certain models, and then the one tagged with the name of a channel will be rendered when that channel is active.

See also

Do you find this information helpful? Please log in to provide feedback.

Last updated: Mar 31, 2014

Recommended reading