Web developers wiki ASP.NET Sitecore Sharepoint Kentico by Evident Interactive

Kentico: using c# within a page template

Modified: 2014/03/14 14:28 by vanthoog - Categorized as: Kentico
The following applies to Kentico v7.0. It probably also applies to previous versions, although this has not been tested.

Edit

Introduction

This article shows two ways of using c# code within a page template when using the Kentico portal engine model.

Edit

Problem description

Suppose you want or need to use c# code in a page template. When using the ASPX page template model, a page template is just an aspx file with a code-behind (aspx.cs) file, so you can just put your c# code in the code-behind file. When using the portal engine model, this is a little bit more difficult because a page template is stored in the Kentico database and does not have a code-behind file. So how can this be done?

Edit

Case description

First let’s start with a simple example. Suppose you have an existing page template containing the following layout:

<div class="content detail">
  <h1>Demo page title</h1>
  <h2>Demo page subtitle</h2>

  <cms:CMSWebPartZone ZoneID="ZoneContent" runat="server" />
</div>

Nothing special, just a hardcoded title and subtitle and one webpart zone.

Suppose the specification changes and suddenly the title must be derived from the document name of the current content item and the subtitle should not be displayed when the content is of field “type” is “opl”. Note: the field “type” is a custom field of a document type.

Edit

First approach: inline script block

The first possible approach is to use an inline script block and to change the h1 and h2 elements into server-side controls:

<script runat="server">
  protected override void OnInit(EventArgs e)
  {
    base.OnInit(e);

    string type = "";
    string title = "Demo page title";

    type = ValidationHelper.GetString(CMSContext.CurrentDocument.GetValue("type"), "");
    title = CMSContext.CurrentDocument.DocumentName;

    h1Title.InnerText = title;
    h2SubTitle.Visible = (type != "opl");
  }
</script>

<div class="content detail">
  <h1 id="h1Title" runat="server"></h1>
  <h2 id="h2SubTitle" runat="server">Demo page subtitle</h2>

  <cms:CMSWebPartZone ZoneID="ZoneContent" runat="server" />
</div>

This works well. However, when you go this template in the CMS Site Manager and switch to the design tab, you will see the following error:

There was an error processing the page. The error can be caused by the configuration of some component on the master page. 
Check the master page configuration or see event log for more details. 
Original message: Object reference not set to an instance of an object.

This error is caused by the fact that there is no cms context in the CMS Site Manager and therefore no current document. To avoid these kind of errors you can test the value of the property CMS.CMSHelper.CMSContext.ViewMode:

<script runat="server">
  protected override void OnInit(EventArgs e)
  {
    base.OnInit(e);

    string type = "";
    string title = "Demo page title";

    if ((CMS.CMSHelper.CMSContext.ViewMode == CMS.PortalEngine.ViewModeEnum.LiveSite 
         || CMS.CMSHelper.CMSContext.ViewMode == CMS.PortalEngine.ViewModeEnum.Preview))
    {
      type = ValidationHelper.GetString(CMSContext.CurrentDocument.GetValue("type"), "");
      title = CMSContext.CurrentDocument.DocumentName;
    }

    h1Title.InnerText = title;
    h2SubTitle.Visible = (type != "opl");
  }
</script>

<div class="content detail">
  <h1 id="h1Title" runat="server"></h1>
  <h2 id="h2SubTitle" runat="server">Demo page subtitle</h2>

  <cms:CMSWebPartZone ZoneID="ZoneContent" runat="server" />
</div>

Here are some advantages of this approach:
- It is fairly simple.

Here are some disadvantages of this approach:
- It is difficult to debug the c# code (i.e. to step through the code in debug mode).
- It can be quite difficult to write c# code in this way because of the lack of intellisense.
- When using a lot of c# code it quickly becomes unreadable and unmaintainable.

Edit

Approach two: user control

The second possible approach is to use a user control and by moving the h1 and h2 element to the user control. So first we have to create a user control (called DemoControl and stored in the folder “~\CMSTemplates\Controls”). Here is the content of the ascx file:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="DemoControl.ascx.cs" Inherits="CMSTemplates_Controls_DemoControl" %>

<h1 id="h1Title" runat="server"></h1>
<h2 id="h2SubTitle" runat="server">Demo page subtitle</h2>

And here is the content of the ascx.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using CMS.CMSHelper;
using CMS.GlobalHelper;

public partial class CMSTemplates_Controls_DemoControl : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
		string type = "";
		string title = "Demo page title";

		if ((CMS.CMSHelper.CMSContext.ViewMode == CMS.PortalEngine.ViewModeEnum.LiveSite 
                     || CMS.CMSHelper.CMSContext.ViewMode == CMS.PortalEngine.ViewModeEnum.Preview))
		{
			type = ValidationHelper.GetString(CMSContext.CurrentDocument.GetValue("type"), "");
			title = CMSContext.CurrentDocument.DocumentName;
		}

		h1Title.InnerText = title;
		h2SubTitle.Visible = (type != "opl");
    }
}


Note: Again a test on the value of the property CMS.CMSHelper.CMSContext.ViewMode is used to avoid errors within the design tab in the CMS Site Manager.

And here is the layout of the page template:

<%@ Register tagprefix="uc" tagname="DemoControl" src="~/CMSTemplates/Controls/DemoControl.ascx" %>

<div class="content detail">
  <uc:DemoControl runat="server" />

  <cms:CMSWebPartZone ZoneID="ZoneContent" runat="server" />
</div>

You may notice one annoying problem when using this approach. When changing the code of the user control, the changes may not be visible on a content item using this page template. To fix this problem, go to the page template in the CMS Site Manager, go to the layout tab and save the page template again.

Here are some advantages of this approach:
- The code is nicely isolated in a user control. The code is therefore easy to maintain.
- It is relatively easy to write the code using intellisense in Visual Studio.
- It is easy to debug the c# code (i.e. to step through the code in debug mode).

Here are some disadvantages of this approach:
- It is slightly more work.
- Changes to the code of the user control may not be directly visible, which makes it a little bit more cumbersome to change the code of the user control.

Edit

What is the best approach?

So which of these two approaches should be used?

First of all the best approach would be to implement this requirement using a webpart. When using the portal engine mode webparts are by far the best way to implement any logic.

If for some reason it is not possible to use a webpart, the preferred approach (in my opinion) is to use a user control because it is easier to write and to maintain the code. I would only use the inline code approach if only a few lines of code are required.

 © Evident Interactive BV