1

My json string including a fixed type header and non-fixed type body as bellow:

[DataContract]
public class ServiceResponseHeader
{
    [DataMember]
    public string ErrorCode { get; set; }

    [DataMember]
    public string Message { get; set; }
}

[DataContract]
public class ServiceResponse
{
    [DataMember]
    public ServiceResponseHeader Header { get; set; }

    [DataMember]
    public object Body { get; set; }
}

At runtime, I can get the type of Body from configuration file, but how can I desterilize the json to the object specified type through DataContractJsonSerializer.ReadObject() ?

The sample code:

string json = @"{ "Header": {"ErrorCode":"0000", "Message":"Got Profile Successfully"}, "Body": [{"DisplayName":"Mike Code","PictureUrl":null,"Title":"Manager"}] }"

Type objType = Type.GetType("MyAssembly.MyTypeName");  //Get Type from configuration file

ServiceResponse obj = new ServiceResponse ()
{
    Header = new ServiceResponseHeader(),
    Body = Activator.CreateInstance(objType)
};

using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
    ServiceResponse returnObj = (ServiceResponse)serializer.ReadObject(ms);
}

Here I can get Header(returnObj.Header.Message) properly, but returnObj.Body is not the type of MyAssembly.MyTypeName and I cannot get it's properties.

Any suggestions for solving such issue?

Yanzhi
  • 73
  • 2
  • 7
  • try "dynamic" if your are using .net 4.0 – Kundan Singh Chouhan Aug 14 '13 at 16:47
  • this may help if body is different types of objects that can be determined by something in the header. http://stackoverflow.com/questions/8241392/deserializing-heterogenous-json-array-into-covariant-list-using-json-net/12727186#12727186 – JimSan Aug 14 '13 at 20:14

3 Answers3

0

Is it feasible to solve this problem by using an interface instead of object, and making use of the "specify known types" version of the DataContractJsonSerializer ( http://msdn.microsoft.com/en-us/library/bb908209.aspx ) ?

It would look something like

var serializer = new DataContractJsonSerializer(typeof(IMySerializable), new [] {
                                                   typeof(ConcreteSerializable1),
                                                   typeof(ConcreteSerializable2)
                                              });

Basically, DataContractSerializer needs context on what you expect it might serialize/deserialize, it can't infer types from the content of the JSON. If you don't want to do that you may want to consider a third party library that will give you more freedom to interpret the JSON as you please. Or the JavaScriptSerializer, but it is slow compared to some third party libraries.

ianschol
  • 586
  • 2
  • 13
  • I am using the following code to test and still cannot deserialize the body the type (ProfileItem) that I specified : var serializer = new DataContractJsonSerializer(typeof(TransactionResponse), new[] { typeof(TransactionResponseHeader), typeof(ProfileItem) }); using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json))) { var obj = (TransactionResponse)serializer.ReadObject(ms); – Yanzhi Aug 15 '13 at 05:25
0

I've always used the JSON.NET library and don't have any experience using the DataContractJsonSerializer, so I'll answer in terms of JSON.NET. Hopefully you'll be able to translate to the DataContractJsonSerializer.


If you define classes like this:

public class MessageHeader
{
    public string TypeName { get; set; }
}

public class Message
{
    public MessageHeader Header { get; set; }
    public JToken Body { get; set; }
}

You can use them like this:

var message = JToken.Parse("...").ToObject<Message>();

if (message.Header.TypeName == "User")
{
    var user = message.Body.ToObject<User>();
}
else if (message.Header.TypeName == "Answer")
{
    var answer = message.Body.ToObject<Answer>();
}

where the User and Answer classes might look something like this:

public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class Answer
{
    public bool IsSolution { get; set;}
    public string Content { get; set; }
}

This will let you handle both this message:

{
    "Header": { "TypeName": "User" },
    "Body": { "Name": "John Smith", "Email": "jsmith@live.com" }
}

and this message:

{
    "Header": { "TypeName": "Answer" },
    "Body" : { "IsSolution": true, "Content": "abc" }
}
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
0

Still cannot find any solution via DataContractJsonSerializer, I have to use JSON.NET to solve this issues, the sample code is as below:

    public static dynamic[] Deserialize(Type headerType, Type bodyType, string json)
    {
        var root = Newtonsoft.Json.Linq.JObject.Parse(json);
        var serializer = new Newtonsoft.Json.JsonSerializer();

        dynamic header = serializer.Deserialize(root["Header"].CreateReader(),headerType);
        dynamic body = serializer.Deserialize(root["Body"].CreateReader(), bodyType);

        return new dynamic[] { header, body };
    }

The headerType is known, the bodyType can be loaded from configuration file (Type bodyType = Type.GetType(configClassName)), this public method will return Header and Body object, then I can convert them into the objects of given types that I wanted.

Yanzhi
  • 73
  • 2
  • 7