This content is archived. See latest version here

Last updated: Mar 25 2013

Table of Contents

Introduction

This document describes the content model when working with different content types in EPiServer CMS.

Tip For an introduction to important concepts in EPiServer CMS, refer to Basic Concepts in EPiServer in the Getting Started part of the SDK.

Using Shared Content – Pages and Blocks

The structure of the website is made up of pages, where the names of the pages automatically form structures and menus. You can create reusable smaller content parts for editing on the pages across your website, also called blocks.

Blocks defines a set of properties. For example a teaser block with a title, a description and maybe an URL to an image. You can define a block both as a property on a page or create a shared block.

Shared blocks are structured using folders in a library. The folder structure is also used to be able to set access rights for blocks. When creating and editing shared blocks you will get a similar experience as when working with pages.

Content areas are properties that are used for displaying a set of content objects such as shared blocks. An editor can manage what content to display by dragging pages and blocks to it. Items that have been added to a content area can be rearranged and deleted. You can also see on which pages each block is used, for example, if you are deleting a block you will be prompted to a dialog that shows you which pages are affected.

Content is separated from their presentation, so pages and blocks can be accessed using the API and rendered on a site using different templates in different context.

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 choosen 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 classe 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
{}

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

[TemplateDescriptor(Inherited = true)]
public partial class MyFallbackTemplate : TemplatePage
{}
public partial class MyPageTeaser : ContentControlBase
{}
[TemplateDescriptor(Inherited = true)]
public partial class PageTeaser : ContentControlBase
{}

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 })%>

When specifying a tag then templates with a matching tag will always be preferred. Tags can also be used for pages.

Previewing Block During 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 template based on context, allowing the editor to switch channels when previewing content. A display channel is 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 Display Channels for more information.

See Also


Do you have feedback on this documentation? Send an email to documentation@episerver.com. For development-related questions and discussions, refer to our Forums on https://world.episerver.com/forum/