HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Create a plug-in

Describes how to create a plug-in for dynamic content using the DynamicContentPluginAttribute and how to add support for MVC to a plug-in.

🚧

Caution

Dynamic content is deprecated in Optimizely Content Management System (CMS 12). Use blocks instead. While existing solutions will continue to work, you should not build new solutions on this API. It will be phased out in the future.

The DynamicContentPluginAttribute simplifies the development and registration of a dynamic content class by eliminating manual registration of your dynamic content class in the <episerver> section of web.config.

📘

Note

Only classes that implement EPiServer.DynamicContent.IDynamicContentBase may be decorated with this attribute, otherwise the application generates an error during startup. However, decorated classes that derive from System.Web.UI.Control implicitly implement IDynamicContent.

  • DisplayName and Description

    • DisplayName is a string used to identify the plug-in in lists.
    • Description is a short text that describes what the dynamic content type does.
  • Url, UrlFromUi, and UrlFromUtil
    Url specifies the path to the user control that handles editing of the dynamic content type. You only have to provide one of these values, choose the attribute that best matches the location of your editing control, use UrlFromUi if the control is located somewhere below the UI folder. The UrlFromUi and UrlFromUtil attributes require relative URLs, and the Url attribute should have an application-relative URL (~/SomeFolder/MyEditControl.ascx).

    If you develop your dynamic content plug-in as a Control, you may choose not to define values for any of the URL attributes. This causes the application to automatically generate a control for editing your dynamic content settings.

  • ViewUrl
    ViewUrl specifies the path to the user control used to render the dynamic content type for visitors. This URL can point to the dynamic content plug-in if you implement it as a user control.

The following example shows a class inheriting from UserControl that is decorated with the DynamicContentPlugInAttribute. Because the class inherits from UserControl you do not have to implement any interfaces, an implicit implementation of IDynamicContentControl is automatically generated based on the settings of the DynamicContentPlugInAttribute and the class public properties.

The value of ViewUrl is an application relative URL pointing to the control's markup file; the control handles the rendering of the Dynamic Content for visitors.

No edit interface URL (Url, UrlFromUI, UrlFromUtil) was specified, so an editorial interface is automatically generated based on the public properties of the class. Only properties of the following types that have the public get and set included in the editorial interface:

[DynamicContentPlugIn(
  DisplayName = "UserControlDynamicContentPlugin",
  Description = "Example of a Dynamic Content plugin as a user control.",
  ViewUrl = "~/Examples/UserControlDynamicContentPlugin.ascx")]
public partial class UserControlDynamicContentPlugin: UserControl {
  // Properties of the following basic types that have public getters
  // and setters are supported by the autogenerated edit interface.
  public string MyString {
    get;
    set;
  }
  public int MyInt {
    get;
    set;
  }
  public bool MyBool {
    get;
    set;
  }

  // The same is true for EPiServer.Core.PageReference...
  public PageReference MyPageReference {
    get;
    set;
  }

  // ...and types inheriting from EPiServer.Core.PropertyData,
  // illustrated here with PropertyString.
  public PropertyString MyPropertyString {
    get;
    set;
  }

  protected void Page_Load(object sender, EventArgs e) {
    if (!IsPostBack) {
      DataBind();
    }
  }
}

The basic markup of the user control in the following example is just for illustration purposes.

<%# MyString %>
<%# MyInt %>
<%# MyBool %>
<%# MyPageReference %>
<%# MyPropertyString %>

Because the class is decorated with the DynamicContentPlugInAttribute, the plug-in is automatically registered and ready for use when the application starts. The following example shows the plug-in in the editorial interface.

597

The following example shows the output for a visitor.

string 8 False 1 PropertyString

Add MVC support for a dynamic content plug-in

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

  • Create a display template with the same name as the dynamic content plug-in.

    For the DynamicPageProperty plug-in, the name is DynamicPageProperty.ascx or DynamicPageProperty.cshtml. The view takes the dynamic content plug-in as the view model and renders the dynamic content in view mode. The following example shows a simple dynamic content (DdsViewerDynamicContent), and a razor view for rendering the content.

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();
      }
    }
  }
}

@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>
  • 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.
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 there is a display template with the same name as the dynamic content plug-in, and the plug-in implements IView, the system calls the display template and ignores the IView implementation.