Sitecore Items and Session State Management on Multiple CD Servers

Share Button

Most developers use the in-process session state management (InProc) during the build of  any website – including Sitecore builds. Sitecore is configured to use InProc session state by default as it’s required to run the Sitecore client on Content Management (CM) servers, this doesn’t apply to the Content Delivery (CD) servers.

So, if the production environment is a single server setup – i.e. one server per environment that provides both the CM and CD roles – developers can get away with storing non-serializable objects in the session – such as Sitecore Items. The website will work without any problems as the In-Proc setup doesn’t do any serialisation.

If the live environment is architected to scale out, i.e load balanced CD servers with load balancer, you can configure your load balancer to use sticky session. In this case, InProc sessions will suffice. The CD servers won’t need to use out-of-process session management such as StateServer and SqlServer. This is by far the quickest solution for the problem. The only drawback is that some load balancing services won’t be able to provide the same sticky session for both http and https requests. So, if a user is redirected to a secure session, there is no guarantee that the load balancer will keep the user on the same server.

If you cannot use sticky sessions on your CD servers, you will have to configure your application to use out-of-process session state management. Once this is done, every object that your application stores in session, will get serialised before being sent to the state server (e.g. SqlServer). Failing to store serialisable objects in the session will always result in throwing serialisation exceptions.

Maybe you have been lucky enough to work in a project before when none of the Dev, Testing or UAT environment were matching the the Live environment in terms of the architecture, especially when it comes to multiple CD servers and load balancing. Unfortunately, this always happens to reduce the cost of the hosting, maintenance, etc. In such setups, it’s more likely to see errors happening only on the Live environment and the serialisation exceptions are one of these problems.

The problem can be solved easily be just marking all your custom classes using the Serializable attribute. However, what happens if your class contains a property of a non-serilaizble type that’s not yours, e.g. Sitecore Item! Well, straight away you may think that you are screwed and probably you need to change the logic of your application to avoid storing such types in session. In some cases, these changes won’t be trivial, and will require code updates affecting several modules, this will also require running functional and regression testing and perhaps bug fixing that may affect the deadline of the project.

Well, the following workaround may help avoiding a crisis.

Ok, let’s start with the following example, a class that contains some properties, one of which is of type Sitecore Item.

public class BadEntity
{
     public string SomeProperty { get; set; }
     public Item Item { get; set; }
}

The following code doesn’t do anything useful, it just stores an object in the session and restores it again. It will run fine if the application is configured to use InProc session state management.

var badEntity = new BadEntity
 {
 SomeProperty = "Some value",
 Item = Sitecore.Context.Item
 };
Session["BadEntityInSession"] = badEntity;
var ent = Session["BadEntityInSession"] as BadEntity;

However, if SateServer or SqlServer session state is used, you will get the following error.

Serialization Exception
Serialization Exception

To fix the error, first you will need to mark the BadEntity Class as Serializable.

[Serializable]
public class BadEntity
{
     public string SomeProperty { get; set; }
     public Item Item { get; set; }
}

Now the Asp.Net knows that BadEntity class can be serialised and it won’t have any problems serialising its fields as long as they are primitive data types such as string, int, etc. So, if you run this code now, you will still get a SerializationException but this time it will complain about the Sitecore.Data.Items.Item type not being serialisable. As you cannot modify the source code of this type to make it Serializable, you can do the following workaround.

[Serializable]
public class BadEntity
{
     [NonSerialized]
     private Item _item;
     private string _itemId;
     public string SomeProperty { get; set; }
     
     public Item Item
     {
       get {return _item;}
       set {_item = value;}
     }
     [OnSerializing]
     public void OnSerializing(StreamingContext context)
     {
         if (Item == null) return;
         _itemId = Item.ID.ToString();
     }

     [OnDeserialized]
     public void OnDeserialized(StreamingContext context)
     {
         if (string.IsNullOrEmpty(_itemId)) return;
         Item = Sitecore.Context.Database.GetItem(new ID(_itemId));
     }
}

The above code will explicitly tell the .Net framework to avoid serialising the property Item as the  _item field is decorated by the NonSerializable attribute. Instead of serialising the item, only its Id will be serialised using the _itemId field. To complete the picture, the OnSerializing and OnDeserialized functions will be automatically called by the .Net framework to provide custom serialisation code for the Item property. Before serialising the entity, the _itemId field will be populated with the Item.ID value. And after deserialising the entity, the _itemId will be used to retrieve the Item from Sitecore.

The solution provided in this article may help you to mitigate a go-live crisis. Although the code looks straight forward, you need to be careful before implementing this solution as it may introduce performance problems into your project.

 

2 Comments

  1. said:

    Is itemID enough to safely model an item, wouldn’t you need to consider language as well?

    February 10, 2015
    Reply
    • ehabelgindy said:

      Good point, I would include the ItemId, Language and Version as well.
      Thanks

      February 11, 2015
      Reply

Leave a Reply

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