1

我的 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 的类型,我无法获取它的属性。

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

4

3 回答 3

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 对象,然后我可以将它们转换为我想要的给定类型的对象。

于 2013-08-15T05:35:00.393 回答
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" }
}
于 2013-08-14T17:17:29.130 回答
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,但与一些第三方库相比它很慢。

于 2013-08-14T17:11:06.480 回答