Being friends with the PropertyControlClassFactory, or: 101 ways to change EPiServer built-in property appearances

As I have been playing around with using ControlAdapters to change the rendering of built-in EPiServer properties lately, I got curious on what else I could possible do to modify them. As it turns out, the EPiServer PropertyControlClassFactory is a great ally in doing this. Hence, this post mostly revolves around different ways of getting it to do what you want. The example source code is available at GitHub through this link.

To show the result of all the examples in this post, I use a line of code that I just threw into the EPiServer AlloyTech sample project footer; hence the pretty blue background in all the images. The default behaviour of this code would be the rendering of a text containing the current page’s name.

<EPiServer:Property runat="server" PropertyName="PageName" />

The RenderingChangedAppearance class of each example looks very much all the same, except that they render a slightly different text depending on which method was used; we concatenate the original output which we get from the ToWebString method (12) with a string of our own (13).

RenderingChangedAppearance.cs

namespace EPiServerBuiltInProperties.CustomizeAppearances .UsingPlugInAttribute
{
  public class RenderingChangedAppearance : PropertyStringControl
  {
    public override void CreateDefaultControls()
    {
      this.Controls.Add(new Literal
        {
          Text = string.Concat(this.ToWebString(),
              " appearance changed using PlugInAttribute.")
        });
    }
  }
}

Change the rendering of a built-in EPiServer property using a plugin attribute

Our first example on how to use the PropertyControlClassFactory to register a new class mapping, making EPiServer use it rather than the default one, is by extending the PlugInAttribute class. When we add a static Start method, it will be called by the EPiServer plugin system during startup; as described by Magnus Stråle in this post on initialization in EPiServer

RegisterAppearance.cs

public class RegisterAppearance : PlugInAttribute
{
  public static void Start()
  {
    PropertyControlClassFactory
       .Instance
       .RegisterClass(typeof(PropertyString),
                      typeof(RenderingChangedAppearance));
  }
}

The result of this is that when we surf to for instance the page named News and Events in the EPiServer AlloyTech sample project we can see that the default rendering does no longer apply; instead we get our own slightly enhanced one.

EPiServer Build-In Property Appearance changed using a PlugInAttribute and PropertyControlClassFactory.

Change the rendering of a built-in EPiServer property using an initialization module

The second example involves creating your own initialization module and having the PropertyControlClassFactory register the mappings there. In order for any initialization module to be run at the start of the application it must at least implement the IInitializableModule interface (or one of its sub interfaces, like IInitializableHttpModule as seen below) and be marked with the [InitializableModule] attribute. Should your initialization module fail and throw an exception during startup, it will re-execute every time a request is made to your application until the error disappears. If you are interested there is plenty of information on this over at EPiServer World.

AppearanceInitializationModule.cs

[InitializableModule]
public class AppearanceInitializationModule : IInitializableHttpModule
{
  public void Initialize(InitializationEngine context) {}
  public void Uninitialize(InitializationEngine context) {}
  public void Preload(string[] parameters) {}

  public void InitializeHttpEvents(HttpApplication application)
  {
    PropertyControlClassFactory
       .Instance
       .RegisterClass(typeof(PropertyString),
                      typeof(RenderingChangedAppearance));
  }
}

Set up your class mappings in the InitializeHttpEvents method and let EPiServer do the rest. Surfing to the News and Events page will give us the following output in the page footer.

EPiServer Build-In Property Appearance changed using an initialization module and PropertyControlClassFactory.

Change the rendering of a built-in EPiServer property using Global.asax

A third option for changing the default appearance of built-in EPiServer properties is through the Global.asax.cs file. In my own humble opinion, this may not be the prettiest way of doing it, but it can be done nonetheless. The key is to have the PropertyControlClassFactory register your mappings in an override of the Init method (8).

Global.asax.cs

public class Global : EPiServer.Global
{
  public override void Init()
  {
    PropertyControlClassFactory
       .Instance
       .RegisterClass(typeof(PropertyString),
                      typeof(RenderingChangedAppearance));
    base.Init();
  }

Once built, the code will output the text as expected when surfing to the example page.

EPiServer Build-In Property Appearance changed using Global.asax and PropertyControlClassFactory.

Change the rendering of a built-in EPiServer property using web.config

The fourth way of having the PropertyControlClassFactory register mappings for our classes brings us into the web.config file; or more specifically, into the classFactories section of the web.config file. I have removed loads of configuration in the snippet below as well as from the example code at GitHub, but the hierarchy of the elements is correct.

web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <episerver.baseLibrary>
    <classFactories>
      <add id="PropertyControlFactory"
           type="EPiServer.Core.PropertyControlClassFactory, EPiServer">
        <register
            type="EPiServer.Core.PropertyString, EPiServer"
            mappedType="EPiServerBuiltInProperties .CustomizeAppearances.UsingWebConfig.RenderingChangedAppearance, EPiServerBuiltInProperties" />

By registering a mapping (7-9) in the classFactories section of the episerver.baseLibrary it is possible to have EPiServer use our customized rendering rather than the default one; just tell the configuration which control it should be swapping out and which to use instead. This time our sample AlloyTech page yields the following.

EPiServer Build-In Property Appearance changed using web.config and PropertyControlClassFactory.

Change the rendering of a built-in EPiServer property using a control adapter

In the final example of this post we will use one of my favourite hammers to solve this problem; a golden control adapter. All jokes aside, changing the appearance may also be done in this way. If you would like to read more on adapters I have some previous posts on the subject.

The way we render the changes is different from when we did an extension of the PropertyStringControl class. Now we extend ControlAdapter (7) and override the Render method (9) instead. The rendering may still be changed, however, by adding controls to the control collection as before.

RenderingChangedAppearance.cs

public class RenderingChangedAppearance : ControlAdapter
{
  protected override void Render(HtmlTextWriter writer)
  {
    Control.Controls
      .Add(new Literal
           {
             Text = " appearance changed using a ControlAdapter."
           });
    base.Render(writer);
  }
}

The mappings are in this case done through an AdapterMappings.browser file in the App_Browsers folder of your web project. Here is what it would look like for our example control adapter in the code snippet above.

AdapterMappings.browser

<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter controlType= "EPiServer.Web.PropertyControls.PropertyStringControl"
               adapterType="EPiServerBuiltInProperties .CustomizeAppearances.UsingControlAdapter .RenderingChangedAppearance" />
    </controlAdapters>
  </browser>
</browsers>

As expected, the rendering of our example text on the News and Events page has changed once more.

EPiServer Build-In Property Appearance changed using a control adapter and PropertyControlClassFactory.

Order of business, or: In what order will these mappings get applied?

On a whim I decided to implement all of the examples at the same time, then removing them one by one to see if I could get an order in which they were applied. What I ended up with was the following.

  1. ControlAdapter
  2. Web.config
  3. PlugInAttribute
  4. Global.asax
  5. InitializableModule

As I know far too little about the inner workings of ASP.NET and EPiServer, I would not bet any vital parts of my system on this order always being the same. However, I found it rather interesting to test though.

Presentation control for properties in Admin mode

It is possible to select different presentation controls for rendering EPiServer properties through Admin Mode. Linus Ekström has written an interesting post about it over at EPiServer labs.

EPiServer Build-In Property Appearance changed, Multiple ways of rendering.