-2

I am facing the following scenario. A project of mine is throwing an event that contains the following object:

public class MyEvent : BaseEvent
{
   public long Id { get; set; }
   public Dictionary<string, long> Pairs { get; set; }
}

I received the event and read the data as byte[] on my receiver side. The current code I have to read any generic event is:

public static T Decode(byte[] data)
{
    var serializer = JsonSerializer.Create(new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Objects,
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    });

    using (var stream = new MemoryStream(data))
    {
        using (var sr = new StreamReader(stream, Encoding.UTF8))
        {
            var jr = new JsonTextReader(sr);
            var aux = Encoding.UTF8.GetString(data);
            return serializer.Deserialize(jr, typeof(T)) as T;
        }
    }
}

where T is my class MyEvent . Unfortunately the thrown exception is:

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.Int64]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path 'OperationTimePairs', line 1, position 61.

The way I read it is that the object received doesn't have the correct format.. however if I try to read it through var aux = Encoding.UTF8.GetString(data); I can see that the structure is the correct one. Any idea how can I fix this? Thanks!

EDIT:

Json Example:

{  
   "Timestamp":"\/Date(1540996292134)\/",
   "Pairs":[  
      {  
         "Key":"first time",
         "Value":28
      },
      {  
         "Key":"second time",
         "Value":30
      },
      {  
         "Key":"third time",
         "Value":101
      },
      {  
         "Key":"operation time",
         "Value":231
      }
   ],
   "Id":123637
}
Tarta
  • 1,729
  • 1
  • 29
  • 63
  • Can you please post a sample json? What do you get after `var aux = Encoding.UTF8.GetString(data);`? – Rui Jarimba Oct 31 '18 at 14:53
  • Also, could you please post the class definition of `BaseEvent`? – Rui Jarimba Oct 31 '18 at 14:54
  • It's giving you a pretty explanatory error message. Instead of using a `Dictionary` use a `List` of a `custom class called Pair` which contains two primitive types of `string` and `long` – Ryan Wilson Oct 31 '18 at 14:54
  • 1
    `To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array.` – Ňɏssa Pøngjǣrdenlarp Oct 31 '18 at 14:59
  • @NewContributor not a duplicate, check out my edit where I post an example of JSON. Mine is a single object, not an array – Tarta Oct 31 '18 at 15:04
  • @RuiJarimba done! – Tarta Oct 31 '18 at 15:08
  • Your dictionary is coming across as an array of key/value pair objects. This is how `DataContractJsonSerializer` serializes a dictionary. `"\/Date(1540996292134)\/"` is also how `DataContractJsonSerializer` serializes a `DateTime` so it's likely this JSON was created by that serializer. There are already several questions asking how to deserialize a dictionary in this format using Json.NET, so I added them as duplicates. Of course the surrogate property approach in the accepted answer also works. – dbc Nov 02 '18 at 14:35

1 Answers1

1

I think that your classes don't match the json string structure.

Given the following json string:

{  
   "Timestamp":"\/Date(1540996292134)\/",
   "Pairs":[  
      {  
         "Key":"first time",
         "Value":28
      },
      {  
         "Key":"second time",
         "Value":30
      },
      {  
         "Key":"third time",
         "Value":101
      },
      {  
         "Key":"operation time",
         "Value":231
      }
   ],
   "Id":123637
}

You can change your models to match the json structure, something like this:

public class MyEvent : BaseEvent
{
    public long Id { get; set; }
    public List<KeyValuePair<string, long>> Pairs { get; set; }

    [JsonIgnore]
    public Dictionary<string, long> PairsDictionary
    {
        get
        {
            if (Pairs == null)
            {
                return new Dictionary<string, long>();
            }

            return Pairs.ToDictionary(pair => pair.Key, pair => pair.Value);
        }
    }
}

public class BaseEvent
{
    public DateTime Timestamp { get; set; }
}

Please note:

  • PairsDictionary is a non-serializable property based on Pairs
  • Given that you didn't provide the class definition of BaseEvent, I will assume that it has 1 property only

Testing the deserialization:

string json = @"{  
""Timestamp"":""\/Date(1540996292134)\/"",
""Pairs"":[  
    {  
     ""Key"":""first time"",
     ""Value"":28
    },
    {  
     ""Key"":""second time"",
     ""Value"":30
    },
    {  
     ""Key"":""third time"",
     ""Value"":101
    },
    {  
     ""Key"":""operation time"",
     ""Value"":231
    }
],
""Id"":123637
}";

MyEvent eventData = JsonConvert.DeserializeObject<MyEvent>(json);

Or as an alternative (using generics):

T data = JsonConvert.DeserializeObject(json, typeof(T)) as T;
Rui Jarimba
  • 11,166
  • 11
  • 56
  • 86
  • **PairsDictionary is a non-serializable property based on Pairs** here is the answer! that's all I needed to know :) thanks a lot! – Tarta Oct 31 '18 at 15:50