Using UserControls instead of XSLT in Sitecore projects

The use of XSLT in Sitecore have been around since Sitecore 4. XSLT’s are fast to write and easy to deploy: All you need to update an XSLT is to copy a new file to your web server.

The nature of an XSLT is to convert XML into other XML (XHTML for example). Sitecore can serialize its content and structure into XML, so using XSLT’s to create the (X)HTML for your website seems to be the correct solution.

However, as the complexity of our web solutions grow, so does our XSLT’s. I have seen XSLT’s with 100′s of lines in them, calling sub templates and even including other XSLT’s. XSLT’s with more than a few lines in them are near-impossible to maintain and leads to mistakes like the “comparing a complete tree structure” error:

<xsl:for-each select="$items[sc:fld('Navigation_Show',.) = '1']">
  // This is wrong: I compare
  // the complete structure with the complete structure
  <xsl:if test=". = $sc_item">
    Do something
  <xsl:if>
  // This is better: Comparing on Sitecore GUIDS
  <xsl:if test="@id = $sc_item/@id">
    Do something
  <xsl:if>
</xsl:for-each>

When including other XSLT’s into a “base” XSLT you start making a yarn ball of code that only you will understand.

One of the primary reasons to choose XSLT’s was that the sc: controls (sc:text, sc:html, …) were the only controls to support inline editing (web edit). However, this obstacle has been removed, as Sitecore has introduced the sc:FieldRenderer webcontrol to be used in User Controls.

<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %>

This control renders the field in web edit mode as well. The FieldRenderer is simple to use:

<sc:FieldRenderer FieldName="Title" runat="server" />

The FieldRenderer is not the only reason you should switch to UserControls.
When sticking to XSLT’s you miss out on the huge Sitecore API that will help you do almost any task with just a few lines of code.
UserControls can be as easy to deploy as XSLT’s (if you stick all of your code into the .ascx file), and you still have access to a code-behind file where you can code all of your business logic as needed.

Now lets see other examples. Here is a simple sub-menu, listing all items below the current item:

<%@ Control Language="c#" AutoEventWireup="true" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %>

<script runat="server">
  void Page_Load(object sender, System.EventArgs e) {
    DataBind();
  }
 
  IEnumerable<Sitecore.Data.Items.Item> SubItems
  {
    get { return Sitecore.Context.Item.Children; }
  }
</script>

<asp:Repeater ID="repSubItems" runat="server" DataSource="<%# SubItems %>">
  <HeaderTemplate>
  </HeaderTemplate>
  <ItemTemplate>
      <a href="<%# Sitecore.Links.LinkManager.GetItemUrl(Container.DataItem as Sitecore.Data.Items.Item) %>">
        <sc:FieldRenderer FieldName="Title" runat="server" Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>" />
      </a>
    </div>
  </ItemTemplate>
  <FooterTemplate>
  </FooterTemplate>
</asp:Repeater>

Here is a breadcrumb. The pattern is almost as the example above:

<%@ Control Language="c#" AutoEventWireup="true" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %><script runat="server">
  void Page_Load(object sender, System.EventArgs e) {
    DataBind();
  }
 
  IEnumerable<Sitecore.Data.Items.Item> Breadcrumb
  {
    get
    {
      List<Sitecore.Data.Items.Item> itemsInPath = new List<Sitecore.Data.Items.Item>();
      Sitecore.Data.Items.Item currentItem = Sitecore.Context.Item;
      Response.Write(currentItem.Key);
      while (currentItem.Key != "content")
      {
        itemsInPath.Add(currentItem);
        currentItem = currentItem.Parent;
      }
      itemsInPath.Reverse();
      return itemsInPath;
    }
  }
 
</script>

<asp:Repeater ID="repBreadcrumb" DataSource="<%# Breadcrumb %>" runat="server">
  <HeaderTemplate>
    <ul>
  </HeaderTemplate>
  <ItemTemplate>
    <li>
      <a href="<%# Sitecore.Links.LinkManager.GetItemUrl(Container.DataItem as Sitecore.Data.Items.Item) %>">
        <sc:FieldRenderer ID="FieldRenderer1" FieldName="Title" runat="server" Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>" />
      </a>       
    </li>
  </ItemTemplate>
  <FooterTemplate>
    </ul>
  </FooterTemplate>
</asp:Repeater>

So do yourself a favor. Take a look at the new possibilities in using UserControls, and consider the use of XSLT’s very carefully before you implement them.

Advertisement

11 Responses to “Using UserControls instead of XSLT in Sitecore projects”

  1. john cooper Says:

    Good points. Also it’s really a hassle to work with xslt files since the language itself is not a programming language it’s a rendering language. You’ll spend a lot of time building something in the obscure language only to find out that you can’t do what you’re trying to do. Variables can be set but not updated and it was never intended to do programming kinds of task. I realize people have concerns about load times and it is faster since there’s no binaries to run but I’ve seen large scale projects with lots of visitors run without any xsl and still have good response time. Also do the next developer on the project a favor and don’t use xslt so when they have to extend your project they’re not forced to rebuild everything. This also applies to all those people who build on Umbraco.

  2. Adam Weber Says:

    hi Brian,

    Great post and great points about why to be careful when choosing to use XSL renderings.

    I admit I’m guilty of having used XSL renderings in my first few Sitecore implementations but quickly realized that maintenance was a nightmare.

    One other point I’d add in favor of using UserControls or WebControls is debugging. It’s much easier to be able to step into the code for a rendering as opposed to trying to track down a rendering issue in XSLT.

    Cheers!
    adam

  3. commodore73 Says:

    Chapter 5 of the Presentation Component Reference has a section about the advantages & disadvantages of the various rendering technologies:

    http://sdn.sitecore.net/Reference/Sitecore%206/Presentation%20Component%20Reference.aspx

    Another reason to use web controls specifically is that you can define your own caching criteria by implementing the GetCachingID() method.

  4. Chris G Says:

    Hi Brian,

    I’m trying out your code for the sub-menu and get this compilation error:
    CS0266: Cannot implicitly convert type ‘Sitecore.Collections.ChildList’ to ‘System.Collections.Generic.IEnumerable’. An explicit conversion exists (are you missing a cast?)

    What do you think might be going on? I was able to get your breadcrumb to work.

    Thanks!
    Chris

  5. briancaos Says:

    Hmm, it must be the Sitecore version. I probably used one of the latest Sitecore 6.2.? or even 6.3.?
    In the later versions of ChildList, it implements IEnumerable, ICollection and IEnumerable which makes the cast possible.

  6. Sitecore Image Parameters « Brian Pedersen’s Sitecore and .NET Blog Says:

    [...] Posts Using UserControls instead of XSLT in Sitecore projectsMultiple languages in SitecoreGSA (Google Search Appliance) Suggest using C# and jQuerySetting up [...]

  7. Creating fallback values using the RenderField pipeline « Brian Pedersen’s Sitecore and .NET Blog Says:

    [...] pipeline is used by the sc:FieldRenderer web control when you render fields from web controls and user controls (.aspx and .ascx files). If [...]

  8. Creating a tree like left menu in Sitecore using UserControls and C# « Brian Pedersen’s Sitecore and .NET Blog Says:

    [...] With Sitecore 5 and Sitecore 6, XSLT’s are becomming deprecated, as it is getting easier and easier to create the same using UserControls. [...]

  9. Using Sitecore EditFrame in PageEdit « Brian Pedersen’s Sitecore and .NET Blog Says:

    [...] Editable from the beginning. Although I would recommend that you rewrite your website using the sc:FieldRenderer. LD_AddCustomAttr("AdOpt", "1"); LD_AddCustomAttr("Origin", "other"); [...]

  10. Sitecore poor database performance « Brian Pedersen’s Sitecore and .NET Blog Says:

    [...] place I would look for performance issues. Most performance issues comes from poor XSLT design (which is why I quit using XSLT’s). Other issues revolve around selecting too many items at once (remember to use the Lucene index). [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 72 other followers