Avoid the use of Sitecore.Context.Item

Or: How Sitecore DMS and Personalization killed the Sitecore.Context.Item. This post is about how to properly ensure that you get data from the correct item when you develop websites that can be personalized.

The Sitecore.Context.Item returns the current item, i.e. the item that corresponds with the URL that the user has entered. Old Sitecore developers like me has been used to adding the fields of a page to the current item, and then accessing these fields directly using the sc:FieldRenderer:

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

<sc:FieldRenderer ID="MyField" runat="server" 
FieldName="NameOfMyField"  />

This approach is no longer a good approach, as the the customer have been given access to DMS and personalization. Now you no longer know if the content that the usercontrol need, is part of the current item, or another item.

Personalize the Component

Personalize the Component

The customer can now acces any component he likes, and use personalization to alter the data source (or even the component itself). This breaks the pattern of assuming that content is part of the current item.

So what can we do?

Before we grab any field, we need to go through these steps:

  • Check the datasource of the current sublayout
  • If the datasource is set, use the item from the datasource
  • If not, use the current item

These 2 extension methods ease the process:

namespace SitecoreExtensions
{
  public static class SublayoutExtensions
  {
    public static Item GetDataSourceItem(this Sublayout sublayout)
    {
      string dataSource = sublayout.DataSource;
      if (string.IsNullOrEmpty(dataSource))
        return (Item) null;
      return Context.Database.GetItem(dataSource);
    }
  }

  public static class UserControlExtensions
  {
    public static Item GetDataSourceItem(this UserControl control)
    {
      Sublayout sublayout = control.Parent as Sublayout;
      return sublayout == null ? (Item) null : SublayoutExtensions.GetDataSourceItem(sublayout);
    }

    public static Item GetDataSourceOrContextItem(this UserControl control)
    {
      return UserControlExtensions.GetDataSourceItem(control) ?? Context.Item;
    }
  }
}

The SublayoutExtensions extend the Sitecore Sublayout. The GetDataSourceItem returns the item that the datasource points at, or null if the datasource is not set.

The UserControlExtensions extend the .NET UserControl (that really is the base of a Sitecore Sublayout). The GetDataSourceOrContextItem returns the datasource item, with a fallback to Sitecore.Context.Item.

To use the method, you must add the function to the item property of the sc:FieldRenderer:

<sc:FieldRenderer ID="MyField" runat="server" 
FieldName="NameOfMyField" 
Item="<%# this.GetDataSourceOrContextItem() %>" />

And you must remember to call DataBind().

This pattern is good because you never end up with a NULL item, as sc:FieldRenderer will crash if you feed it with a NULL value in the item property. There is no reason to crash the entire page just because one component is not configured correct.

From code-behind you simply replace Sitecore.Context.Item with this.GetDataSourceOrContextItem:

var text = Sitecore.Context.Item["NameOfMyField"]; // old way
var text = this.GetDataSourceOrContextItem()["NameOfMyField"]; // new way

I would not be surprised if Sitecore in the future would build these functions into sc:FieldRenderer, but untill then we have to do it ourselves.

Advertisement

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, Sitecore 7 and tagged , , , , , , . Bookmark the permalink.

9 Responses to Avoid the use of Sitecore.Context.Item

  1. In Sitecore 7 update1 you can use: this.Attributes[“sc_datasource”];

    Like

  2. briancaos says:

    Yes, Sitecore is getting there. Next thing they need to do is to extend Sitecore.Context with Sitecore.Context.DataSourceItem and Sitecore.Context.DataSourceOrCurrentItem. Then they need a new attribute in sc:FieldRenderer that checks the datasource with fallback to the current item.

    Like

  3. FYI, the Sublayout Parameter Helper has actually been out for years now and it handles this too.

    http://marketplace.sitecore.net/en/Modules/Sub_Layout_Parameter_Helper.aspx

    Like

  4. dsolovay says:

    Really interesting recommendation. But does it make sense to have a Context property give different values based on which rendering you are in? That breaks the metaphor of all the other Context values, which are at a request level.

    Like

  5. briancaos says:

    I agree that Sitecore.Context.Item should return the request level item, but I do not agree that sc:FieldRenderer by default should use this item as context. The fieldrenderer should primarily look at the datasource, and fall back to the Sitecore.Context.Item. And Sitecore should provide another property, say Sitecore.Context.DataSource or Sitecore.Context.DataSourceOrConextItem which is then the way to get your values from Sitecore.

    Like

  6. Pingback: How to make a customized control for the Page Editor | Visions In Code

  7. Pingback: Make your own Droplink control for the Sitecore Page Editor | Visions In Code

  8. Pingback: Extend the Sitecore FieldRenderer | Brian Pedersen's Sitecore and .NET Blog

  9. Pingback: Which of my old Sitecore posts are still valid in Sitecore 9? | Brian Pedersen's Sitecore and .NET Blog

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 )

Facebook photo

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

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.