Reputation: 85
We are deserializing the JSON using C# System.Runtime.Serialization.Json.DataContractJsonSerializer. It is working for normal objects but not for List.
For example if the json string is below then it works fine:
{"CacheInsertDateTime":"\/Date(1360761324878)\/","Data":{"__type":"SomeObject:#ConsoleApplication1","Symbol":"some string"}}
But if the josn is below:
{"CacheInsertDateTime":"\/Date(1360761324878)\/","Data":[{"__type":"SomeObject:#ConsoleApplication1","Symbol":"some string"},{"__type":"SomeObject:#ConsoleApplication1","Symbol":"some other string"}]}
The data comes as List<Object>
not List<SomeObject>
. I attached the sample solution also, showing the same problem. Any help or direction is appreciated.
EDIT: added the code
{
namespace ConsoleApplication1 { class Program { /* Someobject class*/ [DataContract] public class SomeObject { public SomeObject(string sym) { this.Symbol = sym; } [DataMember] public string Symbol { get; set; }
}
/* Cahe Data */
[DataContract()]
[KnownType("GetKnownTypes")]
class CacheData
{
[DataMember()]
public object Data { get; set; }
[DataMember()]
public DateTime CacheInsertDateTime { get; set; }
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
return GetKnownTypes();
}
public static IEnumerable<Type> GetKnownTypes()
{
if (knownTypes == null)
{
// Since reflection is costly, we will do the lookup once for the known types and persist the data in knownTypes variable
knownTypes = new List<Type>();
// first add types from DataModel assembly get types which are marked with DataContract attribute
var typesInCurrentAssembly = Assembly.GetExecutingAssembly().GetTypes().Where
(t => t.GetCustomAttributes(false).Any(attrib => attrib is DataContractAttribute));
foreach (var type in typesInCurrentAssembly)
{
// add type and list<type> also to the known types list
knownTypes.Add(type);
knownTypes.Add(typeof(List<>).MakeGenericType(type));
}
knownTypes.Add(typeof(DataTable));
}
return knownTypes;
}
private static List<Type> knownTypes = null;
}
/*Cache Response Class*/
class CacheResponse<T> where T : class
{
public CacheData CacheData { get; set; }
public T Data
{
get{return (CacheData != null && CacheData.Data.GetType() == typeof(T)) ? CacheData.Data as T: null;}
}
}
/* Main class */
static void Main(string[] args)
{
//1. first with someobject, it works same as above
string jsonString = "{\"CacheInsertDateTime\":\"\\/Date(1360761324878)\\/\",\"Data\":{\"__type\":\"SomeObject:#ConsoleApplication1\",\"Symbol\":\"some object 1\"}}";
CacheData obj = null;
byte[] byteData = Encoding.UTF8.GetBytes(jsonString);
using (MemoryStream stream = new MemoryStream(byteData))
{
var serializer = new DataContractJsonSerializer(typeof(CacheData));
obj = serializer.ReadObject(stream) as CacheData;
}
CacheResponse<SomeObject> response1 = new CacheResponse<SomeObject>();
response1.CacheData = obj;
SomeObject responseObj = response1.Data; //this response object is fine
//2. with list<someobject>, it does not work
jsonString = "{\"CacheInsertDateTime\":\"\\/Date(1360761324878)\\/\",\"Data\":[{\"__type\":\"SomeObject:#ConsoleApplication1\",\"Symbol\":\"some object 1\"},{\"__type\":\"SomeObject:#ConsoleApplication1\",\"Symbol\":\"some object 2\"}]}";
byteData = Encoding.UTF8.GetBytes(jsonString);
using (MemoryStream stream = new MemoryStream(byteData))
{
var serializer = new DataContractJsonSerializer(typeof(CacheData));
obj = serializer.ReadObject(stream) as CacheData;
}
CacheResponse<List<SomeObject>> response2 = new CacheResponse<List<SomeObject>>();
response2.CacheData = obj;
List<SomeObject> responseList = response2.Data;//this is null
}
}
}
Upvotes: 1
Views: 618
Reputation: 8408
Make sure to let the serializer know what types to expect in the list, for example by passing it to the constructor of DataContractJsonSerializer
.
The following example works as expected:
namespace ConsoleApplication1
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
public class SomeObject
{
public string Symbol { get; set; }
}
public class MyClass
{
public DateTime CacheInsertTime { get; set; }
public List<object> Data { get; set; }
}
public class Program
{
private const string JsonString = @"{""CacheInsertDateTime"":""\/Date(1360761324878)\/"",""Data"":[{""__type"":""SomeObject:#ConsoleApplication1"",""Symbol"":""some string""},{""__type"":""SomeObject:#ConsoleApplication1"",""Symbol"":""some other string""}]}";
private static void Main()
{
var ser = new DataContractJsonSerializer(typeof (MyClass), new[] {typeof (SomeObject)});
var ms = new MemoryStream(Encoding.ASCII.GetBytes(JsonString));
var obj = (MyClass) ser.ReadObject(ms);
Trace.Assert(obj.Data.Count == 2);
Trace.Assert(((SomeObject) obj.Data[1]).Symbol == "some other string");
}
}
}
Note how I pass typeof(SomeType) to the constructor of the serializer.
Upvotes: 0