C# Tip Article
Bug Fix: Invalid viewstate / Unable to find assembly
Bug Fix: Invalid viewstate / Unable to find assembly
An exception was thrown from a ASP.NET WebForms page. It complained about something wrong in ViewState and unable to deserialize the view state information.
[SerializationException: Unable to find assembly 'App_Web_test.aspx.88cc05ae.oewwgbdr, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.] System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly() +2513650 System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name) +133 System.Runtime.Serialization.Formatters.Binary.BinaryConverter.TypeFromInfo(BinaryTypeEnum binaryTypeEnum, Object typeInformation, ObjectReader objectReader, BinaryAssemblyInfo assemblyInfo, InternalPrimitiveTypeE& primitiveTypeEnum, String& typeString, Type& type, Boolean& isVariant) +267 System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadArray(BinaryHeaderEnum binaryHeaderEnum) +355 System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run() +714 System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) +206 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) +206 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) +15 System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +1507 [ArgumentException: The serialized data is invalid.] System.Web.UI.ObjectStateFormatter.Deserialize(Stream inputStream) +230 [ViewStateException: Invalid viewstate. Referer: https://test.com/test.aspx ViewState: /wEPDwUKLTI5NDI1MjI3Mw8WAh4NRmVhdHVyZWRQYWdlczL3GQABAAAA/////wEAAAAAAAAAD....(elided)...] [HttpException (0x80004005): The state information is invalid for this page and might be corrupted.] System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) +169 System.Web.UI.ViewStateException.ThrowViewStateError(Exception inner, String persistedState) +14 System.Web.UI.HiddenFieldPageStatePersister.Load() +251 System.Web.UI.Page.LoadPageStateFromPersistenceMedium() +219 System.Web.UI.Page.LoadAllState() +43 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +8431 System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +253 System.Web.UI.Page.ProcessRequest() +78 System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +21 System.Web.UI.Page.ProcessRequest(HttpContext context) +49
One interesting error message is "Unable to find assembly App_Web_test.aspx.88cc05ae.oewwgbdr". This assembly is a dynamically generated assembly and stays on the web server. That is, if there are multiple web servers using load balancer (Web Farm), round trip request can go to another web server. And that was the case. Most of time consecutive requests from the same client went to the same server where the dynamic assembly resided, but it was not always guaranteed. Hence the error.
So does this error alway occur whenever we use ViewState in Web Farm environment? No, it does not occur if we do not use custom user type. If there is custom user type and the user type object is saved to (or retrieved from) ViewState, ASP.NET generates dynamic assembly for it and performs serialization and deserialization.
Here is an example using ViewState for custom type.
[Serializable] public class ImageData { public int? Id { get; set; } public int? SortOrder { get; set; } public string ImagePath { get; set; } } //... private void LoadData() { List<imagedata> imgData = GetDataFromDB(); ViewState["ImgData"] = imgData; //problematic! //... }
So how can we get around this? One way might be converting custom type object to JSON string before assigning it to ViewState. Here is a small class that does convert object to JSON and retrieve object from JSON.
using System.Web.Script.Serialization; public class ViewStateConverter<T> where T : class { public static string ToJson(T source) { var jss = new JavaScriptSerializer(); return jss.Serialize(source); } public static T FromJson(string jsonString) { var jss = new JavaScriptSerializer(); return jss.Deserialize<T>(jsonString); } }
And with this ViewStateConverter class, the problematic code can be rewritten as follows.
private void LoadData() { List<ImageData> imgData = GetDataFromDB(); ViewState["ImgData"] = ViewStateConverter<List<ImageData>>.ToJson(imgData) //... }