Custom Item Pattern
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 |
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 />
<% } %>
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.
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