如何在C#中使用固定类型标头和变体类型主体反序列化JSON?

时间:2013-08-14 16:37:01

标签: c# .net json json-deserialization

我的json字符串包括固定类型标题和非固定类型主体如下:

[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; }
}

在运行时,我可以从配置文件中获取Body的类型,但是如何通过DataContractJsonSerializer.ReadObject()将json消毒到指定的对象类型?

示例代码:

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);
}

这里我可以正确获取Header(returnObj.Header.Message),但是returnObj.Body不是MyAssembly.MyTypeName的类型,我无法获取它的属性。

有任何解决此类问题的建议吗?

3 个答案:

答案 0 :(得分:0)

通过使用接口而不是对象,并使用DataContractJsonSerializer(http://msdn.microsoft.com/en-us/library/bb908209.aspx)的“指定已知类型”版本来解决此问题是否可行?

看起来像

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

基本上,DataContractSerializer需要您可能序列化/反序列化的上下文,它不能从JSON的内容推断类型。如果您不想这样做,您可能需要考虑第三方库,它将为您提供更多自由来解释JSON。或者JavaScriptSerializer,但与某些第三方库相比,它很慢。

答案 1 :(得分:0)

我一直使用JSON.NET库并且没有使用DataContractJsonSerializer的经验,所以我将回答JSON.NET。希望您能够翻译为DataContractJsonSerializer


如果你定义这样的类:

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

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

您可以像这样使用它们:

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>();
}

UserAnswer类可能如下所示:

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; }
}

这将让您处理此消息:

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

和此消息:

{
    "Header": { "TypeName": "Answer" },
    "Body" : { "IsSolution": true, "Content": "abc" }
}

答案 2 :(得分:0)

仍然无法通过DataContractJsonSerializer找到任何解决方案,我必须使用JSON.NET来解决这个问题,示例代码如下:

    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 };
    }

headerType是已知的,bodyType可以从配置文件中加载(Type bodyType = Type.GetType(configClassName)),这个公共方法将返回Header和Body对象,然后我可以将它们转换为给定类型的对象我想要。