JSON.NET deserialize BindableCollection failing in CM 1.1

Topics: Bugs
Jul 24, 2011 at 4:58 PM
Edited Jul 24, 2011 at 4:59 PM

Hey Rob,

I have a BindableCollection that I serialize into JSON during Deactivate, and then re-serialize it during Activate. This worked fine in CM1.0. I recently upgraded this app to 1.1 and it's throwing an exception on my SerializationHelper

 throws: 

Attempt to access the method failed: Caliburn.Micro.BindableCollection`1.OnDeserialized(System.Runtime.Serialization.StreamingContext)

I was able to work around it by opening INPC.cs line 437 and adding "public" to the method. Which apparently allows JSON.NET to access the method during deserialization.

I'm not really sure what common guidelines for this OnDeserialized attribute are. Should the method be private? Maybe it's an issue with JSON.NET?

[OnDeserialized]
public void OnDeserialized(StreamingContext c) {
    IsNotifying = true;
}

 

Full stack trace provided below:

   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Newtonsoft.Json.Serialization.JsonContract.InvokeOnDeserialized(Object o, StreamingContext context)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IWrappedCollection wrappedList, JsonReader reader, String reference, JsonArrayContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String reference)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueProperty(JsonReader reader, JsonProperty property, Object target, Boolean gottenCurrentValue, Object currentValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IWrappedCollection wrappedList, JsonReader reader, String reference, JsonArrayContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.<>c__DisplayClass1.<CreateAndPopulateList>b__0(IList l, Boolean isTemporaryListReference)
   at Newtonsoft.Json.Utilities.CollectionUtils.CreateAndPopulateList(Type listType, Action`2 populateList)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateAndPopulateList(JsonReader reader, String reference, JsonArrayContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String reference)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
   at BusTrack.Client.SerializationHelper.Deserialize[T](String serialized)
   at BusTrack.Model.RouteCollection.LoadFromCache(Func`2 deserialize)
   at BusTrack.Model.RouteCollection.Initialize(Func`2 deserialize)
   at BusTrack.Client.Framework.BusTrackBootstrapper.InitBusWatch()
   at BusTrack.Client.Framework.BusTrackBootstrapper.OnLaunch(Object sender, LaunchingEventArgs e)
   at Microsoft.Phone.Shell.PhoneApplicationService.FireLaunching()
   at Microsoft.Phone.Execution.NativeEmInterop.FireOnLaunching()

JsonConvert.DeserializeObject<T>(serialized);

Jul 24, 2011 at 9:02 PM

It could be, indeed, a small bug on Json.NET (the MSDN doc uses a private method: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializedattribute.aspx).
It seems that the OnDeserialized support is a recent addition in Json.NET: http://json.codeplex.com/SourceControl/changeset/changes/61773; that's likely why you hit the bug just recently.
The related Json.NET test cases seem to be built using "internal" modifier.