Loading...
Area: Optimizely CMS

Recommended reading 

Note: This topic has no later version.

This document describes how you create page templates in EPiServer CMS, through using ASP.NET Web Forms or MVC. Both are fully valid to use.

Creating a page template

Create a page template in Visual Studio as follows:

  1. In the Solution Explorer context menu, select Add new item.
  2. Select the EPiServer node.
  3. Select the Page Template item and enter a name for the new template.
  4. Click OK.

Using the page templates

When the strongly typed page type template is used, the template will automatically be registred as a supported template for the specified page type (T). To make the template supported for all page types in the system, EPiServer.Core.PageData can be used as the generic type (T).

The [TemplateDescriptor] attribute can be used on templates to add metadata to the template. The attribute can also be used to set the template as the default template for the page data. For more information about the TemplateDescriptor attribute see the Attributes article.

It is possible to use several [TemplateDescriptor] attributes on the same template, to specify several page types which will have the template as an supported render. When the template are strongly typed, the ModelType type must be derived from the generic type. When two page types should use one template, the multi-attribute functionality can be used by setting the generic type to PageData and add two [TemplateDescriptor] attributes, which specifies the types in the ModelType property.

C#
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAnnotations;
using EPiServer.Framework.DataAnnotations;
using EPiServer.SpecializedProperties;
using EPiServer.Web;

[ContentType]
public class MyPage : PageData
{
    public virtual XhtmlString MainBody { get; set; }
    public virtual PageList MainList { get; set; }
}

[TemplateDescriptor(Name = "My template", Description = "My first template", Path = "~/templates/MyTemplate.aspx", Default = true)]
public partial class MyTemplate : TemplatePage<MyPage>
{ }

Creating a block control

Create a block template in Visual Studio as follows:

  1. In the Solution Explorer context menu, select Add new item.
  2. Select the EPiServer node.
  3. Select the Block Template and enter a name for the new template.

The template will automatically be registered as a supported template for the specified block type (T). To make the template supported for all block types in the system, EPiServer.Core.BlockData can be used as the generic type (T).

The [TemplateDescriptor] attribute can be used on controls to add meta data to the template. The attribute can also be used to set the control as the default template for the block data. The attribute, which exists in the EPiServer.Framework.DataAnnotations namespace, contains the following properties:

  • Path is the path to the template to be rendered. Needs to be set if folder structure does not follow namespace structure. There is a namespace convention where the file will be searched for in the path according to the namespace. For example if there is a usercontrol with type CodeSamples.Templates.Units.MyBlockControl then the Path will be resolved if it is located in a folder structure that follows the namespace. So if there is a folder Templates in the application root and it has a sub folder Units where the file MyBlockControl.ascx is located then the Path will be found and hence Path does not need to be set.
  • ModelType is the block data type. It can be used when several [TemplateDescriptor] attributes are used on the same control, to specify several block types which will have the control as an supported render. The ModelType type must be derived from the generic type.
  • Default defines the control as the default control for the block data type.
  • Name is the name of the control.
  • Description contains a description of the control.
  • Inherited means that when this property is set to true, all block data types, which inherits from the ModelType type/Generic type will get the control as a supported control.
C#
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAnnotations;
using EPiServer.Framework.DataAnnotations;
using EPiServer.SpecializedProperties;
using EPiServer.Web;

[ContentType(DisplayName = "A page list", Description = "A block of properties needed to display a page list")]
public class PageList : BlockData
{
    public virtual PageReference Root { get; set; }
    public virtual int Count { get; set; }
    public virtual string Heading { get; set; }
}

[TemplateDescriptor(Name = "My block control", Description = "My first block control", Path = "~/templates/MyBlockControl.ascx", Default = true)]
public partial class MyBlockControl : BlockControlBase<PageList>
{ }

Creating a page template using MVC

Basic template

If you want to render an MVC view for a page type, create a controller which inherits from EPiServer.Web.Mvc.PageController<T>, where T is your page type. This controller will be called for the page type, if it is chosen as the render for the page type. To render EPiServer CMS properties you use the Html.PropertyFor extension method. This method will call another view, which has the same name as the property type you are about to render. For EPiServer built-in properties, we have created views which will render the properties. An example of a view:

C#
public class AcmeStandardPageController : PageController<MyStandardPage>
{
    public ActionResult Index()
    {
        return View();
    }
}

[ContentType]
public class MyStandardPage : PageData
{
    public virtual string MyText { get; set; }
}

An alternative to use Html.PropertyFor is to use the HTML helpers in the EPiServer.Web.Mvc.Html namespace. Those helpers will be called through Html.DisplayFor, but can also be used directly.

  • Html.CategoryList
  • Html.Fragment
  • Html.PageLink
  • Html.UrlLink
  • Html.XForm
  • Html.RenderXForm
  • Html.BeginXForm
  • Html.EndXForm
  • Html.XhtmlString
  • Html.RenderXhtmlString

Dynamic content

You can make a dynamic content plug-in to support MVC in the following ways:

The first option is to create a display template with the same name as the dynamic content plug-in. For the DynamicPageProperty plug-in, the name would be “DynamicPageProperty.ascx” or “DynamicPageProperty.cshtml”. The view will take the dynamic content plug-in as the view model, and render the dynamic content in view mode. In the example “DdsViewerDynamicContent”, we have created a simple dynamic content, and a razor view for rendering the content.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EPiServer.DynamicContent;
using EPiServer.PlugIn;
using EPiServer.Data.Dynamic;
using EPiServer.Core;

namespace CodeSamples.Additional_Content.HowTo
{
    /// <summary>
    /// Dynamic content showing the first 100 items in a Dynamic Data Store.
    /// A specific editor is used to select store.
    /// </summary>
    [GuiPlugIn(Url = "~/EPiServer/DynamicContent/DdsViewerDynamicContentEdit.ascx", Area = PlugInArea.DynamicContent)]
    public class DdsViewerDynamicContentUsingRazor : IDynamicContentBase
    {
        /// <summary>
        /// Gets and sets the selected store
        /// </summary>
        public string State
        {
            get;
            set;
        }

        /// <summary>
        /// This property is not used, because a specific editor is used.
        /// </summary>
        public PropertyDataCollection Properties
        {
            get { return null; }
        }

        /// <summary>
        /// Gets the first 100 hits from the selected store
        /// </summary>
        public IEnumerable<PropertyBag> Top100
        {
            get
            {
                return DynamicDataStoreFactory.Instance.GetStore(State).ItemsAsPropertyBag().Take(100).ToList();
            }
        }
    }
}
C#
@using CodeSamples.Additional_Content.HowTo
@model DdsViewerDynamicContent

<h2>Store: @Model.State</h2>

<table>
@if (@Model.Top100.Count() > 0) { 
    <tr>
        @foreach (string column in @Model.Top100.First().Keys)
        { 
            <th>@column</th>
        }
    </tr>
}

@foreach (var propertyBag in @Model.Top100)
{ 
    <tr>
        @foreach (var value in propertyBag.Values) {
            <td>@value</td>
        }
    </tr>
}
</table>

The second option is to let the plug-in implement the interface System.Web.Mvc.IView, which is exactly what the DynamicPageProperty does. The interface only contains the method Render, with a ViewContext object and a TextWriter.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EPiServer.DynamicContent;
using EPiServer.PlugIn;
using EPiServer.Data.Dynamic;
using System.IO;
using System.Web.Mvc;
using EPiServer.Core;

namespace CodeSamples.Additional_Content.HowTo
{
    /// <summary>
    /// Dynamic content showing the first 100 items in a Dynamic Data Store.
    /// A specific editor is used to select store.
    /// </summary>
    [GuiPlugIn(Url = "~/EPiServer/DynamicContent/DdsViewerDynamicContentEdit.ascx", Area = PlugInArea.DynamicContent)]
    public class DdsViewerDynamicContentUsingIView : IDynamicContentBase, System.Web.Mvc.IView
    {
        /// <summary>
        /// Gets and sets the selected store
        /// </summary>
        public string State
        {
            get;
            set;
        }

        /// <summary>
        /// This property is not used, because a specific editor is used.
        /// </summary>
        public PropertyDataCollection Properties
        {
            get { return null; }
        }

        /// <summary>
        /// Gets the first 100 hits from the selected store
        /// </summary>
        public IEnumerable<PropertyBag> Top100
        {
            get
            {
                return DynamicDataStoreFactory.Instance.GetStore(State).ItemsAsPropertyBag().Take(100).ToList();
            }
        }

        /// <summary>
        /// Renders the data received from the selected store
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="writer">The writer.</param>
        public void Render(ViewContext context, TextWriter writer)
        {
            foreach (PropertyBag propertyBag in Top100)
            {
                foreach (var value in propertyBag)
                {
                    writer.Write(value);
                }
            }

        }
    }
}

If it exists a display template with the same name as the dynamic content plug-in, and the plug-in implements IView, the display template will be called, and the system will not care about the IView implementation.

XForms

To render an XForm property on a page, the HTML helper methods Property and RenderPropertyXForm can be used in the view. The Property method will use the default behavior, while the RenderPropertyXForm takes the name of the property, and an XFormParameters class as parameters. The XFormParameters parameter is optional, and can be used to override the default settings.

The most important properties on the XFormParameters class are SuccessAction and FailedAction. When those properties are not set, default views for succeded and failed posts will be used. By changing those properties to Success for the SuccessAction and Failed for FailedAction, the action Success or Failed will be called in the controller, depending if a validation error occured when posting the form. The methods Success and Failed must than be created in the controller to make it work.

C#
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%@ Import Namespace="EPiServer.XForms.Util" %>

<section id="form">
    <%--<% Html.EnableClientValidation(); %>--%>
    <%: Html.ValidationSummary() %>
    <% Html.RenderPropertyXForm("XForm", new XFormParameters() { SuccessAction = "Success", FailedAction = "Failed" }); %>
    <%--<%: Html.Property("XForm") %>  --%>
</section>

Configuration

For EPiServer CMS to be able to match a requested URL to a controller, the EPiServer.Web.HierarchicalUrlRewriteProvider class must be in use. In a newly installed site that is the default URL rewrite provider, but in the case of an upgrade you must change the configuration manually.

Creating a block control using MVC

You can render an MVC view for a block type in the following ways:

  • Create a controller which inherits from EPiServer.Web.Mvc.BlockController<TBlockData>, where TBlockData is your block type. This controller will be called for the block type, if it is chosen as the render for the block type. In the EPiServer.Web.Mvc.BlockController<TBlockData> there is an implementation of the action Index, which will call a partial view with the same name as the block type.
  • Create a partial view with the same name as the block type. If the view is chosen as the render for the block type, the view will be called with the page data object directly, without any controller getting involved.

To render EPiServer CMS properties you use the procedure as you do on pages that is described above.

Managing client resources when developing templates

It is possible to require certain client resources to be rendered on the page in specific area. Please see Managing client resources in EPiServer CMS section for more information about requirements for templates to support this functionality.

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

Last updated: Mar 31, 2014

Recommended reading