1

For .NET. I've tried a lot of different things, but nothing seems to work. Requirements:

  1. The T of ObservableCollection<T> is an ISerializable
  2. The ObservableCollection-derived-class ideally is also an ISerializable
  3. For this context, being an ISerializable = uses only ISerializable technique for serialization, not reflected properties

Environment is Xamarin for Android, I'd prefer to use either JSON.NET or DataContractJsonSerializer. Example uses Newtonsoft 9.0.1

With code like this:

[Serializable]
[KnownType(typeof(ObservableCollectionSerializable.Item))]
public class ObservableCollectionSerializable : 
    ObservableCollection<ObservableCollectionSerializable.Item>
{
    [Serializable]
    public class Item : ISerializable
    {
        readonly string value;

        public Item(string value) { this.value = value; }

        public Item(SerializationInfo info, StreamingContext context)
        {
            value = info.GetString("value");
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("value", value);
        }
    }
}

Invoked like this:

            var _item = new Test.ObservableCollectionSerializable.Item("test1");
            var c = new Test.ObservableCollectionSerializable();

            c.Add(_item);

            var serializer = new Newtonsoft.Json.JsonSerializer();
            serializer.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver()
            {
                //IgnoreSerializableInterface = false // not available
            };
            var stringWriter = new StringWriter();

            serializer.Serialize(stringWriter, c);

            var json = stringWriter.ToString();                

            var stringReader = new StringReader(json);

            var c2 = (Test.ObservableCollectionSerializable)
                serializer.Deserialize(stringReader, typeof(Test.ObservableCollectionSerializable));

            var item = c2[0];

Results are:

  • "json" variable always ends up "[{}]" - empty
  • ISerialize-based methods are never called
  • serializer.Deserialize call always throws exception "Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type Notos.App.UI.Android.Test.ObservableCollectionSerializable+Item. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path '[0]', line 1, position 3"
Malachi
  • 2,260
  • 3
  • 27
  • 40
  • cant you just convert your `ObservableCollection` to `T[]` and then serialize it ? – Felix D. Aug 22 '16 at 07:35
  • 3
    JSON.NET works just fine for this. What didn't work for you? – Aleksey L. Aug 22 '16 at 07:40
  • 1
    1) Can you share a [mcve] for this problem? 2) If using Json.NET, be sure that you have not set [`DefaultContractResolver.IgnoreSerializableInterface = true`](http://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Serialization_DefaultContractResolver_IgnoreSerializableInterface.htm). 3) If your custom collection also has properties, see [How to serialize/deserialize a custom collection with additional properties using Json.Net](https://stackoverflow.com/questions/14383736) or [JSON.Net Serializing Derived Classes](https://stackoverflow.com/questions/32062025). – dbc Aug 22 '16 at 07:57
  • @dbc IgnoreSerializableInterface property was not available for me. @Nudity even attempting as `T[]` json variable ends up empty – Malachi Aug 22 '16 at 16:40
  • The example code works fine in my environment. I see the value of json as `[{"value":"test1"}]` – RQDQ Aug 22 '16 at 16:57
  • @RQDQ good to know; are you in Xamarin for Android, or elsewhere? – Malachi Aug 22 '16 at 16:59
  • What version and implementation of Json.NET for xamarin are you using? – dbc Aug 22 '16 at 16:59
  • @dbc it's 9.0.1 targetframework="monoandroid60". The path includes "portable-net45+wp80+win8+wpa81". Is it possible a dependent assembly is pulling in an older version and messing up things? – Malachi Aug 22 '16 at 17:07
  • 1
    You could do `Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);` to be sure. Also, Newtonsoft doesn't have a xamarin build, does it? What build are you using? – dbc Aug 22 '16 at 17:16
  • Verified, using 9.0.0 assembly. Correct, no Xamarin build, this one seems to be the PCL build for .NET 4.5 – Malachi Aug 22 '16 at 17:26
  • 1
    `IgnoreSerializableInterface` and `IgnoreSerializableAttribute` are not available for the `DOTNET || PORTABLE || PORTABLE40` builds. See the [reference source](https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs#L169). Maybe try this instead? https://components.xamarin.com/view/json.net – dbc Aug 22 '16 at 18:32
  • 1
    @dbc good insight. I tried the 7.0 one hosted as a Xamarin component (verified with assembly.FullName) and same result. It appears PCL(and legacy Android) build may currently exclude ISerialization support? – Malachi Aug 22 '16 at 19:48
  • @Malachi - xamarin claims to have ISerializable: https://developer.xamarin.com/api/type/System.Runtime.Serialization.ISerializable/ so I don't know why the xamarin component doesn't have it. Sorry I can't be more help. Maybe there's some sort of security issue? See here https://msdn.microsoft.com/en-us/library/system.runtime.serialization.isafeserializationdata(v=vs.110).aspx – dbc Aug 22 '16 at 20:01
  • 1
    @dbc for real. I have used ISerializable for other scenarios in Xamarin/Mono. Based on our comments, I tried brute forcing the non-PCL net45 newtonsoft build and actually it works! I'd consider this a workaround not a solution since updates will probably break it – Malachi Aug 22 '16 at 20:41

0 Answers0