Creating a custom Sitecore-like Context

Often when working in Sitecore we extend the solution using pipeline processors, one of the most common being the httpRequestBegin pipeline. This is also where a lot of the Sitecore goodness happens – site resolving, database resolving, device resolving, language resolving and item resolving – amongst many others.

Resolving things can be expensive. It takes up precious processing time and cpu cycles, so when you have to run a piece of code you only want to do that once. It’s the same reason that Sitecore puts a lot of data into the Context object for use throughout the request. So it would be handy if we could resolve our own code only once and make it available during the request as well.

Extending Sitecore Context

A simple way to achieve this is to use Sitecore.Context.Items:

Sitecore.Context.Items["my-key"] = "my-value";

In fact, this is not any different than what goes on under the scenes when Context.Item is set:

public static Item Item
{
  get
  {
    return Switcher<Item, ContextItemSwitcher>.CurrentValue ?? Context.Items["sc_CurrentItem"] as Item;
  }
  set
  {
    Context.Items["sc_CurrentItem"] = (object) value;
  }
}

Using the value stored in the collection throughout your code is straight forward enough:

var myValue = Sitecore.Context.Items["my-key"];

Custom Context

It’s also possible to create our own Sitecore-like Context to provide a strongly typed object. The values will be available throughout the current request and only for this request, in much the same way as the Sitecore Context object.

using Sitecore.Caching;
using Sitecore.Data;

namespace MyProject.Custom
{
    /// <summary>
    /// Custom Request Context like Sitecore.Context
    /// Allows us to extend our own strongly typed implementation
    /// and is available for this single request cycle
    /// </summary>
    public class Context
    {
        private static readonly ItemsContext _items;
        private static ItemsContext Items
        {
            get
            {
                return _items;
            }
        }

        static Context()
        {
            _items = new ItemsContext();
        }

        const string idKey = "myproject::ID";
        public static ID Id
        {
            get
            {
                if (Items[documentKey] == null)
                {
                    return null;
                }
                return Items[idKey] as ID;
            }
            set
            {
                Items[idKey] = value;
            }
        }

        const string documentKey = "myproject::Document";
        public static IDocumentItem Document
        {
            get
            {
                if (Items[documentKey] == null)
                {
                    return null;
                }
                return Items[documentKey] as DocumentItem;
            }
            set
            {
                Items[documentKey] = value;
            }
        }
    }
}

Now in our code we can simple call

Item ResolvedItem = ResolveCurrentItem();
IDocumentItem document = ResolveCurrentDocument();

MyProject.Custom.Context.Id = ResolvedItem.ID;
MyProject.Custom.Context.Document = document;

ID customID = MyProject.Custom.Context.Id;
String docTitle = MyProject.Custom.Context.Document.Title;
String docID = MyProject.Custom.Context.Document.ID;

Buyer Beware

Be careful about holding too much information using either option. Only hold the minimum information you need to, and make use of Sitecore functionality to render your data as needed.

I’ll follow up with some practical usage in a future post.

Thanks to Steve McGill for pointing me towards this solution a very long time ago.

Further Reading:
Sitecore Trivia: How Can The Sitecore.Context.Item Property Be Static?
When can we use HttpContext.Current.Items to stores data in ASP.NET?

2 comments

  1. is this code thread safe?

    • jammykam · March 29, 2016

      I’m not sure exactly what you mean. Your request will run in a single thread and it’s as Thread-safe as Sitecore.Context… so yes. But it totally depends on the context (no pun intended) that you are using it.

Leave a comment