2013-08-14 3 views
1

Ma chaîne JSON, y compris un en-tête de type fixe et le corps de type non fixe comme ci-dessous:Comment désérialiser JSON avec un en-tête de type fixe et un corps de type variant en C#?

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

Lors de l'exécution, je peux obtenir le type de corps du fichier de configuration, mais comment puis-je desterilize JSON à l'objet type spécifié via DataContractJsonSerializer.ReadObject()?

L'exemple de 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); 
} 

Ici, je peux obtenir en-tête (returnObj.Header.Message) correctement, mais returnObj.Body est pas le type de MyAssembly.MyTypeName et je ne peux pas obtenir ses propriétés.

Des suggestions pour résoudre ce problème?

+0

essayez "dynamique" si vous utilisez .net 4.0 –

+0

cela peut aider si le corps est différents types d'objets qui peuvent être déterminés par quelque chose dans l'en-tête. http://stackoverflow.com/questions/8241392/deserializing-heterogenous-json-array-into-covariant-list-using-json-net/12727186#12727186 – JimSan

Répondre

0

ne peut toujours pas trouver de solution par DataContractJsonSerializer, je dois utiliser JSON.NET pour résoudre ce problèmes, la code de l'échantillon est comme ci-dessous:

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

le headertype est connu, le bodyType peut être chargé à partir du fichier de configuration (type bodyType = Type.GetType (configClassName)), cette méthode publique retournera l'objet En-tête et Corps, alors je peux les convertir en objets de types donnés que je voulais.

0

Est-il possible de résoudre ce problème en utilisant une interface au lieu d'un objet, et en utilisant la version "spécifier les types connus" du DataContractJsonSerializer (http://msdn.microsoft.com/en-us/library/bb908209.aspx)?

Il ressemblerait à quelque chose comme

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

Fondamentalement, DataContractSerializer a besoin le contexte de ce que vous attendez peut linéariser/désérialiser, il ne peut pas déduire les types de contenu du JSON. Si vous ne voulez pas faire cela, vous pouvez envisager une bibliothèque tierce qui vous donnera plus de liberté pour interpréter le JSON à votre guise. Ou le JavaScriptSerializer, mais il est lent par rapport à certaines bibliothèques tierces.

+0

J'utilise le code suivant pour tester et je ne peux toujours pas désérialiser le corps le type (ProfileItem) que je spécifiée: var sérialiseur = new DataContractJsonSerializer (typeof (TransactionResponse), le nouveau [] { typeof (TransactionResponseHeader), typeof (ProfileItem) }); en utilisant (MemoryStream ms = nouveau MemoryStream (Encoding.UTF8.GetBytes (json))) { var obj = (TransactionResponse) serializer.ReadObject (ms); – Yanzhi

0

J'ai toujours utilisé la bibliothèque JSON.NET et n'ai aucune expérience en utilisant le DataContractJsonSerializer, donc je répondrai en termes de JSON.NET. J'espère que vous serez en mesure de traduire au DataContractJsonSerializer.


Si vous définissez des classes comme ceci:

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

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

Vous pouvez les utiliser comme ceci:

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

où les classes User et Answer pourrait ressembler à ceci:

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

Cela vous permettra de gérer à la fois ce message:

{ 
    "Header": { "TypeName": "User" }, 
    "Body": { "Name": "John Smith", "Email": "[email protected]" } 
} 

et ce message:

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