InvalidCastException from StateServer session

1.4k Views Asked by At

A site I've written is experiencing a strange issue whereby it suddenly doesn't recognize items stored in the session immediately after I've made any update to the code. I've searched Stackoverflow / google / etc and can see that some other people have the same problem but can't find a solution anywhere.

Here's roughly what's happening:

If I add an item to my basket it stores a List<BasketItem> in the session. If I then make an update to some code (not BasketItem) the session variable still exists but .NET doesn't seem to think the it's a List<BasketItem> even though it definately is.

When I try and retrieve the list of basket items after modifying the code it throws an InvalidCastException which just doesn't make any sense as it's basically trying to say the types it's converting between are different even though they are not.

The exception is:

System.InvalidCastException: [A]System.Collections.Generic.List1[BasketItem] cannot be cast to [B]System.Collections.Generic.List1[BasketItem]. Type A originates from 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' in the context 'LoadNeither' at location 'C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll'. Type B originates from 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' in the context 'LoadNeither' at location 'C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll'.

I'm using StateServer for the session state and running ASP.NET 3.5 SP1 if that helps.

The code I'm using is below:

// for setting the basket
List<BasketItem> basketItems = new List<BasketItem>();
Session["basket"] = basketItems;

// for getting the basket
List<BasketItem> basketItems = (List<BasketItem>)Session["basket"];

For the moment I'm using 'as casting' so I doesn't error but it does mean user's basket's are being lost when the code is updated.

Any advice would be much appreciated!

Cheers

Tim

1

There are 1 best solutions below

1
On BEST ANSWER

This type of problem is pretty common due to how BinaryFormatter stores the underlying type data, which can cause problems if that they doesn't resolve to exactly the same BasketItem that you had in mind. Most frequently, this hurts when changing the version of your application / library, or when there are different servers with different states.

My strong advice here is: don't let it use BinaryFormatter to store the state! It is not very version friendly, in both this regard and a few other issues within a type. If it is possible, I urge you to consider strong contract-based data instead (meaning: virtually anything other than BinaryFormatter / NetDataContractSerializer). Examples:

  • you could use JavaScriptSerializer and store a basic string of the data
  • you could use XmlSerializer and store a basic string of the data
  • if you want binary, you could use protobuf-net and strore a byte[] of the data

You would obviously then use helper methods to store/retrieve your data, normally with a generic void Store<T>(string key, T object) and T Retreive<T>(string key), using typeof(T) internally as-necessary. The advantage of this is that the stored data is now neutral of any particular implementation, and can be consumed by other versions of your application (since nothing is type-dependent), and even by other platforms (Java, php, etc) if necessary.

I appreciate this is a side-step around the problem rather than a direct solution - but: it works.