The Best Way to Compare Two Content References in Episerver

In this guide, we’re going to talk a bit about ContentReferences, the different ways you can compare them and then give advice about the recommended approach. I came across a snippet of code that, from first glance, looks reasonable but caused a subtle bug in the code meaning a link to a content page didn’t work as expected.

What is a content reference?

A content reference is the default Episerver data type that is used to reference content within your Episerver website.

In the early days of Episerver, a content reference refereed to a page within Episerver. Since the IContent interface was introduced in Episerver 7 onwards, a content reference can be anything that implements from it. Content references can now be a link to page, block, an image or even custom data within a service that sits outside of Episerver.

When a content item that implements the IContent interface is saved into the EPiServer database, a corresponding entry is made within the Episerver database and a unique numeric primary key is created and associated with that content item.

To reference that content we can create a new ContentReference with the corresponding primary key ID, call the Api and return the content. For example say the database Id from some content is 4 we could use the following code to retrieve it:

var contentReference = new ContentReference(4);
var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
var theContent= contentLoader.Get<PageData>(contentReference );

In a real world application you would never have hard-coded database Id’s in your code base, but you get the idea. Now we can get content, what happens if we want to compare if two content reference are equal? You may very well be tempted to do this:

var itemOne = new ContentReference(4);
var databaseId = 4;
itemOne.ID == databaseId;

This might look like a perfectly logical bit of code but it contains a very subtle bug. All Episerver database Id’s are unique, however, there may be more than one data source for content within Episerver. As Episerver allows for multiple data sources for content, you may have several bits of content that have the same numeric ID, so we need to further method to differentiate content.

Having multiple content data sources within your project

If you look within a ContentReference you will find a property called ‘ProviderName’. The provider name is the way you can differentiate between the different content providers registered in the system.

A lot of developers, when comparing ContentReference, will just compare the two ID properties. This code may work fine for ages, but, in the future, if a second content provider was introduced, bugs could mysteriously start appearing for no apparent reason. It’s this reason why you should always use the ID and the provider name to check for content reference equality.

Before we finish the theory behind ContentReferences, there is one more point to consider… versioning.

How to version content in Episerver

The last bit of the content reference puzzle is versioning. In a real world website content changes frequently. Every time a bit of content is saved it is given a new version Id. In Episerver word the version Id that is assigned to a bit of content is called the WorkID. When you compare content you also need to be aware of the different versions In some circumstances you may want to retrieve or compare versions.

var itemOne = new ContentReference
{
ID = 1,
WorkdID = 1
}
var itemTwo = new ContentReference
{
ID = 1,
WorkdID = 2
}
var result = itemOne == itemTwo;

In the scenario above the result will be false because the versions are different.

How do I compare versions?

Episerver 8

Thanks to Matt, who left a comment below about this, but, as of Episerver 8 the best way to compare two content references is to use the standard .Net equals method. From Episerver 8 on-wards we have a new  ContentReferenceComparer class that can be used to perform an Equals() or Compare() between two ContentReference.

Equals

var contentRef1 = new ContentReference();
var contentRef2 = new ContentReference();
var contentReferenceComparer = new ContentReferenceComparer();
bool result = contentReferenceComparer.Equals(contentRef1, contentRef2);

Compare

var contentRef1 = new ContentReference();
var contentRef2 = new ContentReference();
var contentReferenceComparer = new ContentReferenceComparer();
int result = contentReferenceComparer.Compare(contentRef1, contentRef2);

Additionally, the development team have also implemented a new Equals() overload on the ContentReference class itself. This Equals the same as the CompareToWorkID method mentioned below and will eventually deprecate it. To compare to content references we should be doing this:

var contentRef1 = new ContentReference();
var contentRef2 = new ContentReference();
contentRef1.Equals(contentRef2);

Episerver 7 and below

If you look through the ContentReference API you should come across CompareToWorkID. CompareToWorkID will compares two ContentReference and ignores the WorkID.

When comparing content references this is the approach that I recommend developers to use to prevent introducing possible bugs. In 90% of the projects I’ve used, I’ve only ever used Episerver as the main data provider.

var itemOne = new ContentReference();
var itemTwo = new ContentReference();
itemOne.CompareToIgnoreWorkID(itemTwo);

Conclusion

In today’s guide, we’ve talked about the different aspects that uniquely identify content within Episerver. These properties are the database id, the version id (work id) and the source that the content has come from (provider name). If you come across code that simply compares content references solely by Id, then take that as a warning sign you have a bug within your code and you need to refactor it.

When you want to compare to content references always use the CompareToIgnoreWorkID method to save yourself from having a number of headaches.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

2 replies
  1. Matthew
    Matthew says:

    Hi Jon

    I think the CompareToIgnoreWorkID is being deprecated after EPiServer v8 according to http://thisisnothing.nystrom.co.nz/2015/02/25/comparing-contentreference-instances/

    Now the recommended equivalent is to use the .net Equals overload found in EPiServer.Core.ContentReference
    // Summary:
    // Indicates whether the current EPiServer.Core.ContentReference is equal to
    // another EPiServer.Core.ContentReference.
    // Parameters:
    // other:
    // A EPiServer.Core.ContentReference to compare with this object.
    // ignoreVersion:
    // Indicates if version information should be excluded from the comparison.
    // Returns:
    // true if the current object is considered equal to the other parameter; otherwise,
    // false.
    public virtual bool Equals(ContentReference other, bool ignoreVersion);

    So, for in your example, it would look like this:
    itemOne.Equals(itemTwo, true);

    Matt 🙂

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *