Don't miss out Virtual Happy Hour this Friday (April 26).

Try our conversational search powered by Generative AI!

Loading...
Area: Optimizely CMS

Recommended reading 

Note: This topic has no later version.

Table of Contents

Introduction

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 Strong typed page type template (recommended) or Page template item and enter a name for the new template.
  4. Click OK.
  5. For the page type template which is not strongly typed, a confirmation box will prompt you whether to create a new EPiServer Page Type for the new page template or not.
    • If you choose to add a corresponding page type, you will be prompted with a new dialog asking for some more information about the page type.
      After completing this, the files will be created and a new entry will be added to the page type table in the contained database.
    • If you select not to add a page type, the page template files will simply be created.

Recommendations for Usage

  • The files will be created (for example: foo.aspx, foo.aspx.cs, foo.aspx.designer.cs). The generated files should have the correct file name.
  • The type defined in the code-behind file should have a name based on the provided file name and be placed in the default namespace for the current project location.
  • The type declared in the code-behind file should derive from 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(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; }
    }
    
    [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>
    { }
    
    [TemplateDescriptor(Name = "My block control", Description = "My first block control", Path = "~/templates/MyBlockControl.ascx", Default = true)]
    public partial class MyBlockControl : BlockControlBase<PageList>
    { }

    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 Strong typed block type 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; }
    }
    
    [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>
    { }
    
    [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

    To be able create page templates through MVC, see System Requirements.

    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 both an display template with the same name as the dynamic content plug-in exists, 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>
    C#
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Success(XFormPage currentPage, XFormPostedData xFormPostedData)
    {
        return View("Success", currentPage);
    }
    
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Failed(XFormPage currentPage, XFormPostedData xFormPostedData)
    {
        return View("Failed", currentPage);
    }

    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 when Working with EPiServer CMS section for more information about requirements for templates to support this functionality.

    Activating the Right-Click Menu

    By default, the right-click menu for the website is disabled for the user interface, but you can activate it by adding a constructor parameter for your page templates. The activation affects the user interface modes in the following way:

    • Default user interface: The activation provides the right-click menu in edit mode.
    • Legacy user interface: The right-click menu is already enabled in edit mode, but the activation provides the right-click menu in view mode.

    The following example shows how to enable the right-click menu in the page template constructor (note that the setting in this example is applied to a template base class, but it is also possible to enable the menu in the constructor for each template):

    public partial class MyBaseTemplate : TemplatePage
        {
            public MyBaseTemplate ()
                : base(EPiServer.Web.PageExtensions.ContextMenu.OptionFlag, 0)
            { }
        }
Do you find this information helpful? Please log in to provide feedback.

Last updated: Mar 25, 2013

Recommended reading