1

After trying almost any solution here on SO (this one is the lastest) I gave up and decided to ask for your help.

I'm trying to serialize/deserialize a collection of objects that extend a common abstract class. Serialization goes fine, but it fails when deserializing, throwing this exception:

'Newtonsoft.Json.JsonSerializationException' in Newtonsoft.Json.DLL

Could not create an instance of type Plugins.BaseModel. Type is an interface or abstract class and cannot be instantiated. Path 'Widgets[0].BackgroundColor', line 1, position 60.

Before goind into the code, here's the string that I'm trying to deserialize (I've indented the string to make it more readable!):

{
  "Widgets": [
    {
      "$type": "SimpleBatteryModel",
      "BackgroundColor": {
        "A": 255,
        "R": 229,
        "G": 20,
        "B": 0
      },
      "ForegroundColor": {
        "A": 255,
        "R": 255,
        "G": 255,
        "B": 255
      },
      "BackgroundOpacity": 1.0,
      "WidgetPosition": {
        "Left": 157.0,
        "Top": 302.0,
        "Right": 0.0,
        "Bottom": 0.0
      }
    },
    {
      "$type": "DummyModel",
      "Text": "Dummy Widget (4)",
      "BackgroundColor": {
        "A": 255,
        "R": 229,
        "G": 20,
        "B": 0
      },
      "ForegroundColor": {
        "A": 255,
        "R": 255,
        "G": 255,
        "B": 255
      },
      "BackgroundOpacity": 1.0,
      "WidgetPosition": {
        "Left": 0.0,
        "Top": 0.0,
        "Right": 0.0,
        "Bottom": 0.0
      }
    },
    {
      "$type": "SimpleBatteryModel",
      "BackgroundColor": {
        "A": 255,
        "R": 229,
        "G": 20,
        "B": 0
      },
      "ForegroundColor": {
        "A": 255,
        "R": 255,
        "G": 255,
        "B": 255
      },
      "BackgroundOpacity": 1.0,
      "WidgetPosition": {
        "Left": 330.0,
        "Top": 0.0,
        "Right": 0.0,
        "Bottom": 0.0
      }
    },
    {
      "$type": "DummyModel",
      "Text": "Dummy Widget (4)",
      "BackgroundColor": {
        "A": 255,
        "R": 229,
        "G": 20,
        "B": 0
      },
      "ForegroundColor": {
        "A": 255,
        "R": 255,
        "G": 255,
        "B": 255
      },
      "BackgroundOpacity": 1.0,
      "WidgetPosition": {
        "Left": 180.0,
        "Top": 700.0,
        "Right": 0.0,
        "Bottom": 0.0
      }
    },
    {
      "$type": "SimpleBatteryModel",
      "BackgroundColor": {
        "A": 255,
        "R": 229,
        "G": 20,
        "B": 0
      },
      "ForegroundColor": {
        "A": 255,
        "R": 255,
        "G": 255,
        "B": 255
      },
      "BackgroundOpacity": 1.0,
      "WidgetPosition": {
        "Left": 0.0,
        "Top": 650.0,
        "Right": 0.0,
        "Bottom": 0.0
      }
    }
  ]
}

(Widgets is an ObservableCollection<BaseModel>)

While I'm not posting my JsonSerializerSettings because I've got this error with any combination of settings, here's a little snippet of my code (focusing just on the serialized properties).

(class namespace Plugins.BaseModel)

[JsonObject(MemberSerialization.OptIn)]
public abstract class BaseModel : ViewModelBase
{
    ...other stuff...        
    [JsonProperty]
    public Color BackgroundColor
    {
        get { return _backgroundColor; }
        set
        {
            if (_backgroundColor == value) return;
            _backgroundColor = value;
            RaisePropertyChanged(() => BackgroundColor);
        }
    }

    [JsonProperty]
    public Color ForegroundColor
    {
        get { return _foregroundColor; }
        set
        {
            if (_foregroundColor == value) return;
            _foregroundColor = value;
            RaisePropertyChanged(() => ForegroundColor);
        }
    }

    [JsonProperty]
    public double BackgroundOpacity
    {
        get { return _backgroundOpacity; }
        set
        {
            if (value == _backgroundOpacity) return;
            _backgroundOpacity = value;
            _backgroundColor.A = (byte) (_backgroundOpacity*255);
            RaisePropertyChanged(() => BackgroundOpacity);
            RaisePropertyChanged(() => BackgroundColor);
        }
    }

    [JsonProperty]
    public Thickness WidgetPosition
    {
        get { return _widgetPosition; }
        set
        {
            if (value == _widgetPosition) return;
            _widgetPosition = value;
            RaisePropertyChanged(() => WidgetPosition);
        }
    }
    ...other stuff...
}

(class Plugins.widgets.PRIVATE.Dummy.DummyModel)

[JsonObject(MemberSerialization.OptIn)]
public class DummyModel : BaseModel
{
 ... other stuff...
 [JsonProperty]
    public string Text
    {
        get { return _text; }
        set
        {
            if (_text == value) return;
            _text = value;
            RaisePropertyChanged(() => Text);
        }
    }
... other stuff ...
}

(class Plugins.widgets.Battery.SimpleBattery.SimpleBatteryModel)

[JsonObject(MemberSerialization.OptIn)]
public class SimpleBatteryModel : BaseModel
{
    ... other stuff ...
}

As you can see, both the concrete classes are inheriting properties from the base class, and those properties are serialized without errors. The problem comes when I try to deserialize, as the deserializer tries to create an instance of the base class instead of the derived one.

Does anyone have a solution to this problem?

EDIT: Since you're sking, here are my current settings (based on the answer linked at the start of the question)

_settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = new TypeNameSerializationBinder("Plugins.{0}, Plugins")};

EDIT 2: Here's my project's structure:

Main Solution
             \- Main App (WP app project)
                        \- MainPage.xaml
             \- Model    (WP C# library project)
                        \- MainViewModel.cs (contains the collection Widgets that I'm serializing)
             \- Plugins  (WP C# library project)
                        \- BaseModel.cs (the main abstract class)
                        \- widgets.PRIVATE.Dummy.DummyModel.cs (one of the concrete classes)
                        \- widgets.Battery.SimpleBattery.SimpleBatteryModel.cs (the other concrete class)

where Main App references Model which references Plugins

Community
  • 1
  • 1
StepTNT
  • 3,867
  • 7
  • 41
  • 82
  • What does your `TypeNameSerializationBinder` look like? – Brian Rogers Dec 06 '13 at 15:28
  • I don't have the project with me now, but I copied the one in this reply: http://stackoverflow.com/a/15881570/1094430 – StepTNT Dec 06 '13 at 15:31
  • OK, thanks. Next question-- are your plugins in different assemblies? – Brian Rogers Dec 06 '13 at 15:35
  • I've added a rough view of my project's structure, check the updated question. – StepTNT Dec 06 '13 at 15:43
  • Thanks for the update. One last question. Have you tried not using the custom binder, but instead setting `TypeNameAssemblyFormat = FormatterAssemblyStyle.Full` (both when serializing and deserializing)? – Brian Rogers Dec 06 '13 at 16:00
  • I've tried it now, serialized output is changed but I got the _same_ exception on deserializing. – StepTNT Dec 06 '13 at 16:43
  • OK, do both of your plugin classes have a default constructor (i.e. a constructor that takes no parameters)? – Brian Rogers Dec 06 '13 at 16:55
  • Everything has a default constructor, even the abstract `BaseModel` class. (shouldn't we move this to chat?) – StepTNT Dec 06 '13 at 17:28
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/42664/discussion-between-brian-rogers-and-steptnt) – Brian Rogers Dec 06 '13 at 17:33
  • Hi, I'm facing a similar problem, how did you get it working finally ? – tobiak777 Oct 09 '15 at 21:44
  • Hi there, I'm sorry but after 2 years it's quite difficult to remember what I did. Probably I just gave up on tha project :( I suggest you to start a new question. – StepTNT Oct 10 '15 at 09:09
  • @StepTNT I'm so sad to hear that =/ yes I did start a new question but nobody seems to know http://stackoverflow.com/questions/32958062/deserialization-nightmare-could-not-create-an-instance-of-type-t-type-is-an I spent 4 days on that, read every question, read all google, read the source code, and so on. I've never been that puzzled by a bug as far as I can remember. – tobiak777 Oct 10 '15 at 15:55

1 Answers1

1

I don't see how you serialize and deserialize but make sure you are using the same JsonSerializerSettings to deserialize as well. It doesn't have to be the same instance but it must have the same options in order to work on deserialization.

Tomasz Jaskuλa
  • 15,723
  • 5
  • 46
  • 73
  • I'm even using the same instance of `JsonSerializerSettings` to serialize and deserialize. – StepTNT Dec 06 '13 at 12:11
  • Well, it was a wild guess as this issue may come from different settings of serialization/deserialization and I haven't seen the code. Have you tried to set TypeNameHandling.Objects in JsonSerializerSettings ? – Tomasz Jaskuλa Dec 06 '13 at 12:15
  • Already tried it. Serialized output changes, but the exception is always the same :\ I've edited my question with my current settings. – StepTNT Dec 06 '13 at 12:17