Custom Item Pattern

4

June 25, 2010 by Alistair Deneys

Once upon a time there was a great Sitecore blogger. He wrote inspiring articles and provided fantastic information and insight to the wider Sitecore community. His blog was a palace of knowledge and the villagers did bask in said knowledge. But alas one day darkness fell on this great blog. For the domain name for the site expired and the wise blogger was left yelling into the darkness trying to restore the great site. I speak of the sage who goes by the name Alexey Rusakov (no link to his site for current obvious reasons).

Yes, recently I was after some information from Alexey’s blog. The article I was after was to do with the custom item pattern for Sitecore coding. But I couldn’t find the information cause the domain name had expired and all URLs to Alexey’s blog ended up on a holding page. Oh no! Have we lost the only reference for the Sitecore custom item pattern?

So in the interests of preserving the coding pattern I will give you my take on this pattern. I haven’t come across that many coding patterns for working with Sitecore. In fact, this is probably the only one I can think of. A lot of the other advise for coding against Sitecore is best practises, not coding patterns.

So what is a custom item? A custom item is a specialised item class which provides all the marshalling of strongly typed data in and out of an item’s fields. This means the code used to parse the data is centralised in the custom item class rather than strewn throughout your website’s code where the data is used. The custom item also provides implicit conversion from a normal item class. This is done to make it easier to convert between a custom item and a normal item.

Here are the facets of the custom item pattern:

  • The custom item class must inherit from the Sitecore.Data.Items.CustomItem class.
  • The custom item class must provide implicit casting from a normal item (Sitecore.Data.Items.Item class) to the custom item class
  • The custom item class must provide properties to access the fields of the custom item in a strongly typed manner.

I do have some reservations about the first facet above, that the custom item class must inherit from the CustomItem base class. I’ve included it on the list cause it’s one of the points I remember from Alexey’s article, though in my opinion inheriting from a specific class is more of an implementation guideline rather than a coding pattern.

For this example I’ll create a data template in Sitecore as follows. I’ll then create a custom item which handles items based on this data template.

Field Title Type Purpose
Title single line text The title of the item
Date DateTime The date and time this item is officially released
Count single line text An integer for how many items to show

custom item data template

As the facets of the custom item pattern dictate above, Sitecore provides a base class which you can use for your custom item classes; Sitecore.Data.Items.CustomItem. So we will inherit from that class. I’ll also provide the constructor required to satisfy the base class as it doesn’t contain a default constructor as well as the implicit operator which enables implicit casting from a normal item.

using System; 
using Sitecore.Data.Items;

namespace CustomItem 
{ 
  public class MyCustomItem : Sitecore.Data.Items.CustomItem 
  { 
    public MyCustomItem(Item innerItem) : base(innerItem) { }

    public static implicit operator MyCustomItem(Item innerItem)
    { 
      return new MyCustomItem(innerItem); 
    }
  } 
}

The constructor takes an item as a parameter. This is the normal item which our custom item wraps and marshals field data in and out of. Let’s fill in the properties of the custom item based on the data template definition above.

public string Title 
{ 
  get 
  { 
    return InnerItem["title"];
  }

  set 
  { 
    InnerItem["title"] = value; 
  }
}

public DateTime DateTime 
{ 
  get 
  { 
    var fld = InnerItem.Fields["date"]; 
    if (fld != null) 
      return ((DateField)fld).DateTime; 
    else 
      return DateTime.MinValue; 
  }

  set 
  { 
    InnerItem["date"] = Sitecore.DateUtil.ToIsoDate(value); 
  } 
}

public int Count 
{ 
  get 
  { 
    var value = 0; 
    int.TryParse(InnerItem["count"], out value); 
    return value; 
  } 

  set 
  { 
    InnerItem["count"] = value.ToString(); 
  } 

}

Note we have both setters and getters to facilitate both the marshalling of data into the field and out of the field in a strongly typed manner. We will however need to take into consideration when updating a field value to ensure the underlying item is in edit mode. There are 2 ways in which to handle this. You can include in each setter the editing transaction calls, or you can allow the user to put the item into edit mode explicitly, then commit the transaction when editing is complete.

If we were to allow each setter to handle the edit calls then the Count property above would become:

public int Count 
{ 
  get 
  { 
    var value = 0; 
    int.TryParse(InnerItem["count"], out value); 
    return value; 
  } 

  set 
  {
    InnerItem.Editing.BeginEdit(); 
    InnerItem["count"] = value.ToString();
    InnerItem.Editing.EndEdit(); 
  } 
}

This approach is OK if you only update 1 field at a time, but you’re losing performance due to all the editing calls if you update multiple fields at a time.

I favour the second approach; allow the caller to put the item into edit mode explicitly then commit the transaction when done. This also behaves more like normal Sitecore items do. Now you may be tempted to just tell developers calling your custom item to just use the publicly available InnerItem property and put the underlying item into edit mode. This is bad. It breaks encapsulation requiring the caller to have knowledge of the inner workings of your class. Instead a better approach is to expose some methods from your custom item to allow control of the edit transaction.

public void BeginEdit() 
{ 
  InnerItem.Editing.BeginEdit(); 
}

public void CancelEdit() 
{ 
  InnerItem.Editing.CancelEdit(); 
}

public void EndEdit() 
{ 
  InnerItem.Editing.EndEdit(); 
}

Now we can use our custom item. I’ve created a simple sublayout which will display the fields of an item based on the data template we created above. In the code behind I’ll expose a property to allow the markup to access the current context item as a custom item.

public partial class Custom_Item_Info : System.Web.UI.UserControl 
{ 
  public MyCustomItem Item 
  { 
    get; 
    set; 
  }

  protected void Page_Load(object sender, EventArgs e) 
  { 
    Item = Sitecore.Context.Item; 
  } 
}

The implicit operator takes care of the conversion for us. And onto the markup of the sublayout.

<% for(var i = 0; i < Item.Count; i++) { %> 
Title: <%= Item.Title %><br /> 
Date: <%= Item.DateTime %><br /> 
<% } %>

 

custom item sublayout

The main benefit of using this coding pattern in your implementations is that it isolates changes to the underlying data templates from your implementation code and centralises parsing logic. If you were to change the field type of one of the fields of the item, or impose some different kind of validation on the field data, then there’s only a single place in your code you need to worry about updating that, your custom item class. This also makes it easier to use data from an item which has a custom item class as your calling code doesn’t have to worry about parsing the data out of the field.

Advertisements

4 thoughts on “Custom Item Pattern

  1. Steve Green says:

    Hi Alistair,

    Cheers for preserving knowledge, especially when it’s Sitecore related 😉

    The custom item class is an awesome feature but there is a performance consideration people should be aware of. I have seen cases where people have implemented it only to find much later in the project that it causes some serious performance problems.

    In one case they had used it to to connect together all the various item relationships, such as article/author, this let them do nice things like “string altText = articleItem.AuthorItem.Portrait.Alt;”. The downside was that none of these objects were lazy loaded so if you only needed “articleItem.Name” you still were creating the AuthorItem object, casting the Portrait field to an ImageField and so on. The end effect of this been that anytime someone fetched a large number of Article items the server would grind to a halt. Going back in and refactoring in lazy loading was possible but hugely time consuming.

    All in all I like the idea but I have seen to many difficulties during implementation. The initial gains made during development often evaporate during testing near the end and I’ve also heard stories of massive difficulty when upgrading Sitecore itself (mostly with new features not been supported by the abstraction layer).

    As with all things though your millage may vary, if you are going to write such an abstraction layer I would recommend first having a look at similar modules in the Shared Source library that can help such as Mark Cassidy’s Domain Objects.
    http://trac.sitecore.net/DomainObjects

    • Alistair Deneys says:

      Thanks Steve,

      It’s great to hear of your experiences. I must say I’ve only seen this pattern used in a simple fashion where no other Items or or complex objects were exposed from the custom item, just simple types. Very good points you make though, and something I think all developers should be aware of when implementing in Sitecore.

  2. Gabriel Boys says:

    We have done a lot of work over the last 4 years using Custom Items. Our company has found them to be really useful to keep access to items/templates centralized. This keeps the code cleaner and easier to figure out, which in turn makes it much easier to bring new developers up to speed on a project. This also make maintenance over time a lot more straightforward.

    A big part of this pattern for us is using code generators to make creating these items an easier process. Often we will have a setup of partial classes like this

    CustomItem1.base.cs
    CustomItem1.interface.cs
    CustomItem1.static.cs
    CustomItem1.instance.cs

    Then we have a UI in Sitecore to recreate the code files for a template. When we run this it overwrites the .base.cs file, but leaves the other files alone. This makes it safe to recreate the items over and over, without having to worry about overwriting an custom code we have written. This is a nice setup also because it gives us logical places to put code related to the template. An easy example would be having a ExpertDisplayName for an expert, this would concatenate the first and last name. Since this would be called for an instance of an ExpertItem (for example), we know the code would go in .instance.cs . We also make heavy use of interfaces when developing sites, having a .interface.cs to centralize where all the implementation code can go really helps keep the code cleaner over time.

    Velir is about 85-90% of the way done with a shared source module that will provide the UI and code generation I mention above. When we release it would be great if you could check it out and give us some feedback.

    As far as performance problems. We must be using these custom items in different ways as we have never noticed any inherent speed issues with this approach. We have at least 10 -15 sites in production right now using this approach. It probably just depends on what you are trying to access through a custom item.

    Gabe

  3. Verndale says:

    Great read…thanks! Very informative. For more on Sitecore CMS implementation go here: http://bit.ly/bZ2S8S

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

Categories

The views expressed on this blog are solely my own and do not necessarily reflect the views of my employer.
%d bloggers like this: