6

Introduction

After implementing private and shared outProc sessions states, I'm receiving the following error. This is a Sitecore 8.1 Update 3 environment. We are using SOLR as our indexer. We are also utilizing EXM. I decided to implement this when a slew of errors in the Content Delivery servers were indicating locked Contact records by the cluster, even though all of the CD's are in the same Analytics.ClusterName.

Error

Unable to serialize the session state. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted. The same restriction applies if similar serialization is done by the custom session state store in 'Custom' mode.

[SerializationException: Type 'Sitecore.ContentSearch.SearchTypes.SearchResultItem' in Assembly 'Sitecore.ContentSearch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.]
System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) +970
System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) +306
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() +188 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) +250
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) +96
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) +710 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) +208 System.Web.Util.AltSerialization.WriteValueToStream(Object value, BinaryWriter writer) +2262

Configuration Settings

Below are the configurations setup. This is a local environment. My environment is currently setup as a single instance, but with private and shared session state enabled. The intended production environment is a distributed environment.

Content Delivery Web.config

<sessionState mode="Custom" customProvider="mssql" cookieless="false" timeout="20" sessionIDManagerType="Sitecore.SessionManagement.ConditionalSessionIdManager">
  <providers>
    <add name="mongo" type="Sitecore.SessionProvider.MongoDB.MongoSessionStateProvider, Sitecore.SessionProvider.MongoDB" sessionType="Standard" connectionStringName="session" pollingInterval="2" compression="true" />
    <add name="mssql" type="Sitecore.SessionProvider.Sql.SqlSessionStateProvider, Sitecore.SessionProvider.Sql" sessionType="private" connectionStringName="session" pollingInterval="2" compression="true" />
  </providers>
</sessionState>

Content Delivery Sitecore.Analytics.Tracking.config

<sharedSessionState patch:source="Sitecore.Analytics.Tracking.config" defaultProvider="mssql">
<providers>
<clear/>
<add name="InProc" type="System.Web.SessionState.InProcSessionStateStore"/>
<add name="mssql" type="Sitecore.SessionProvider.Sql.SqlSessionStateProvider,Sitecore.SessionProvider.Sql" connectionStringName="session" pollingInterval="2" compression="true" sessionType="shared" patch:source="Client.config"/>
</providers>
<manager type="Sitecore.Analytics.Tracking.SharedSessionState.SharedSessionStateManager, Sitecore.Analytics">
<param desc="configuration" ref="tracking/sharedSessionState/config"/>
</manager>
<config type="Sitecore.Analytics.Tracking.SharedSessionState.SharedSessionStateConfig, Sitecore.Analytics">
<param desc="maxLockAge">5000</param>
<!--
 If an item in session state is already locked, this parameter is the time in milliseconds that the system is idle before making another attempt to apply a lock. 
-->
<param desc="timeoutBetweenLockAttempts">10</param>
</config>
</sharedSessionState>

Intended Environment Setup

  • 1 Primary CM Server
  • 1 Secondary CM Server / Processing
  • 3 Content Delivery Servers, load balanced.
    • Heavy use of Analytics and xDB Contact Records

Research Done

On Sitecore's Known Issues for Sitecore 8, there is a mention of what seems to be a similar issue. But they don't list a Public Reference Number.

A number of dialogs could not be opened on Content Management servers with out-of-process session-state configured. This happened because the pipeline arguments were not serialized correctly. This has been fixed to ensure that these dialogs function properly, however please note that other Sitecore functions (in an out-of-process session-state server configuration) may not be supported as a result of this fix.

Summary

This looks like a bug in the Sitecore Content Search DLL. Has anyone come across this? I can't imagine that no one else uses OutProc private / sharesession states in a distributed environment.

  • Have you implemented custom search? Do you put anything search-related into: 1) the user's session? 2) the current interaction? 3) the current contact? If you do any of these three things, that's the problem - the interaction and the contact are serialized into the session/shared session. – Dmytro Shevchenko Oct 22 '16 at 17:53
  • Wouldn't it report that the error stack trace would be coming from that object then and not ContentSearch specifically? That being said, I'll have to check. I don't think we're manipulating the users session interaction or the contact with search related information. – Pete Navarra Oct 22 '16 at 17:55
  • The only stack trace I'm seeing starts in System.Web.Util.AltSerialization.WriteValueToStream. That's ASP.NET internals, not ContentSearch. – Dmytro Shevchenko Oct 22 '16 at 18:04
  • It looks like you're trying to put into session object using (or inheriting) from SearchResultItem. – Marek Musielak Oct 22 '16 at 18:16
  • 1
    I figured this out finally... Of particular interest is the red herring of the Type that it was saying was not serializable, "SearchResultItem" in ContentSearch. -- I found two places where HttpContext.Current.Session[key] was being utilized to store a KeyValuePair<DateTime,List<IInterfaceObject>>. IInterfaceObject -- Anyways, I fixed it by chaging the storage of that item and not using session for it. Worked like a charm! EDIT: I'll type up an answer to show my solution once I get a moment. – Pete Navarra Oct 23 '16 at 3:47
10

Background

What the error message means is that an object of type SearchResultItem could not be serialized as part of a session that is saved to a session store. There are two types of sessions used by Sitecore: private session (a.k.a. ASP.NET session) and shared session.

SearchResultItem is a class that is used to retrieve results when querying indexes through the Sitecore search API. Sitecore does not store these objects in sessions out of the box, which means that some code in your solution does.

As your question is described right now, and without going through your code base, it is impossible to provide you with a concrete solution. So here's the general solution:

Do not attempt to put non-serializable objects into session.

Below you can find some concrete advise on finding the offending code.

Look through all usages of both ASP.NET session API and Sitecore session API

  • See where and how HttpContext.Current.Session is used;
  • Check if your code uses Sitecore's SharedSessionStateManager directly;
  • Check if your code attaches any custom objects to:

    • Tracker.Current.Interaction;
    • Or Tracker.Current.Session.Interaction;
  • Check if your code attaches any custom objects to:

    • Tracker.Current.Contact;
    • Or Tracker.Current.Session.Contact.

The reason you need to check Interaction and its child objects is because the current interaction is saved to the ASP.NET session at the end of every request.

The reason you need to check Contact and its child objects is because the current contact is saved to the Sitecore shared session at the end of every request.

For all of the above instances, verify that no custom objects that may be saved to the session are of class SearchResultItem, and that no custom objects contain SearchResultItem objects at any nesting level.

Look through all usages of SearchResultItem

Perform a solution-wide search for "SearchResultItem" and see where and how it is used. If you see that these objects may be saved into private or shared session, review this approach:

  • Consider whether you need to store these objects, at all;
  • If you do, then consider storing them elsewhere;
  • If you, for some reason, do need to store them in the session, then create a custom serializable type that is stored instead of the Sitecore native SearchResultItem.
  • This is a great answer Dmytro. There's an interesting element to this that has me a bit confused. I don't know whether to make it an answer to explain, or leave it in comments.. but the object being stored in the session object was a `KayValuePair<DateTime,List<IContentItemInterface>>. This has nothing to do with Content Search SearchResultItem. Except that through DEBUG, the object being returned through the interface was a "SearchResultItem" class.. except belonging to a client library.. and inherited from "Sitecore.Data.Items.CustomItem". Not Content Search. Working that piece solved it. – Pete Navarra Oct 23 '16 at 20:05
  • @PeteNavarra Well, it sounds to me like it's very specific to your solution. So it's unlikely to help anyone else not familiar with your code base? But if you can make a more generic answer that can be useful to others, then by all means, go ahead! – Dmytro Shevchenko Oct 24 '16 at 6:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.