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;
      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.

Advertisements

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in c#, General .NET, Sitecore 6 and tagged , , , , , . Bookmark the permalink.

15 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. Pingback: Sitecore Image Parameters « Brian Pedersen’s Sitecore and .NET Blog

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

  8. Pingback: The Gloo » Sitecore certification looks cool, but what do you learn?

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

  10. Pingback: Using Sitecore EditFrame in PageEdit « Brian Pedersen’s Sitecore and .NET Blog

  11. Pingback: Sitecore poor database performance « Brian Pedersen’s Sitecore and .NET Blog

  12. Alexander says:

    I could not disagree more. And when I saw Response.Write(currentItem.Key); in a property getter I understood I did not have to read further.

    If you would have favoured a viewengine like Spark or Razor above XSLT I could understand. But not ASP.NET. This is a dinosaur. The problem with ASP.NET is that it is unmaintainable and hard to follow. Especially when people start writing HTML to the Response output from everywhere.

  13. Pino says:

    Plz dont use Response.Write in a property getter. And dont use the Asp.Net WebControls as it is not always easy to control how they render. Which can be a headache for front-end developers (the CSS and HTML specialists).

    But ok. I do not completely agree with you. We are using XSLT’s for about 95% of the rendering. We are using UserControls only for some of the Forms that we have on the site. But I do see your point. For us the golden combination was putting the rendering in XSLT’s and putting business logic (calculations) and complex operations (operations too complex for XSLT, this includes string.ToUpper, string.Trim, url formatting etc.) in XSLT extension methods. This way we could have only the rendering of HTML in the XSLT. And because we have the rendering in XSLT’s our front-end developers can easily make changes if needed. Also a small fix only requires a release of a single XSLT instead of compiling the entire site and releasing it again.

    But: do one thing, inherit a class from Sitecore’s XslUtility and override the item (sc:item) method. By default it returns the /sitecore/content item when the path is empty (this can happen with broken links, or coding errors) instead have it return an empty XPathNodeIterator.

    Happy coding,
    Pino

  14. briancaos says:

    The Response.Write(currentItem.Key); is a mistake from my side and is just used as a debug statement.
    And it’s true that some WebControls render in strange ways (TreeView, GridView etc) which is why I usually uses Repeaters and ListViews.
    Years ago I also used XslExtensions for complex operations, but it has some drawbacks. When doing XslExtensions you fall back to programming procedural code instead of object oriented code. And in time the extensions keep getting more complex, drifting into business logic. And when you get to that point you will experience that when your extensions is in fact business logic it difficult to organize your code into reusable, independent components.
    You should try making one simple project without XSLT’s and you will find that after a day or so of coding you don’t miss XSLT’s anymore.

  15. briancaos says:

    The Response.Write(currentItem.Key); is a mistake from my side and is just used as a debug statement.
    ASP.NET is not a dinosaur. It’s just another platform just as Spark, Razor or whatever you favor.
    The point of the article is that you should not use XSLT’s because if you do you will not have access to the VERY extensive Sitecore ASP.NET library.
    It does not matter if you like User controls, Spark and Razor, as long as you bave access to Sitecores library, and you don’t if you keep transforming XML with XSLT.
    Usercontrols are supported by Sitecore out-of-the-box. Later Sitecore versions (6.6x) support MVC and other developers have successfully implemented Razor views. But the easiest way of developing a healty component based Sitecore solution is still to use Usercontrols.

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 )

Google+ photo

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

Connecting to %s