2017-10-03 5 views
1

Je suit JSON que j'écris modèle d'objet à désérialiser dans:Désérialisation de JSON, les propriétés d'objets imbriquées doivent être dans l'objet parent. C#

{ 
    "company_webhooks": [ 
    { 
     "company_webhook": { 
     "id": 42, 
     "url": "https://keeptruckin.com/callbacktest/842b02", 
     "secret": "fe8b75de0a4e5898f0011faeb8c93654", 
     "format": "json", 
     "actions": [ 
      "vehicle_location_received", 
      "vehicle_location_updated" 
     ], 
     "enabled": false 
     } 
    }, 
    { 
     "company_webhook": { 
     "id": 43, 
     "url": "https://keeptruckin.com/callbacktest/a6a783", 
     "secret": "66a7368063cb21887f546c7af91be59c", 
     "format": "json", 
     "actions": [ 
      "vehicle_location_received", 
      "vehicle_location_updated" 
     ], 
     "enabled": false 
     } 
    }, 
    { 
     "company_webhook": { 
     "id": 44, 
     "url": "https://keeptruckin.com/callbacktest/53a52c", 
     "secret": "4451dc96513b3a67107466dd2c4d9589", 
     "format": "json", 
     "actions": [ 
      "vehicle_location_received", 
      "vehicle_location_updated" 
     ], 
     "enabled": false 
     } 
    }, 
    { 
     "company_webhook": { 
     "id": 45, 
     "url": "https://keeptruckin.com/callbacktest/6fb337", 
     "secret": "4177fbd88c30faaee03a4362648bd663", 
     "format": "json", 
     "actions": [ 
      "vehicle_location_received", 
      "vehicle_location_updated" 
     ], 
     "enabled": false 
     } 
    }, 
    { 
     "company_webhook": { 
     "id": 46, 
     "url": "https://keeptruckin.com/callbacktest/8cd6da", 
     "secret": "6e41817a048b009435e5102fca17db55", 
     "format": "json", 
     "actions": [ 
      "vehicle_location_received", 
      "vehicle_location_updated" 
     ], 
     "enabled": false 
     } 
    } 
    ], 
    "pagination": { 
    "per_page": 25, 
    "page_no": 1, 
    "total": 5 
    } 
} 

Voici ce que j'ai:

[DataContract] 
public class KeepTruckinResponse 
{ 
    [DataMember(Name = "company_webhooks", EmitDefaultValue = false)] 
    public KeepTruckinCompanyWebHook[] WebHooks { get; set; } 

    [DataMember(Name = "pagination", EmitDefaultValue = false)] 
    public KeepTruckinPagination Pagination { get; set; } 

    public string RawJSON { get; set; } 
} 

[DataContract] 
public class KeepTruckinPagination 
{ 
    [DataMember(Name = "per_page", EmitDefaultValue = false)] 
    public int PerPage { get; set; } 

    [DataMember(Name = "page_no", EmitDefaultValue = false)] 
    public int PageNumber { get; set; } 

    [DataMember(Name = "total", EmitDefaultValue = false)] 
    public int Total { get; set; } 
} 

[DataContract(Name = "company_webhook")] 
public class KeepTruckinCompanyWebHook 
{ 
    [DataMember(Name = "id", EmitDefaultValue = false)] 
    public int Id { get; set; } 

    [DataMember(Name = "url", EmitDefaultValue = false)] 
    public string Url { get; set; } 
} 

Il est évident que, quand je deserialize JSON je ne reçois pas KeepTruckinCompanyWebHook propriétés parce que la façon dont ils envoient la collection est "imbriquée". Je dois presque créer un autre objet à l'intérieur KeepTruckinCompanyWebHook avec des propriétés. Mais j'aimerais garder mon modèle d'objet tel quel. Est-il possible avec le sérialiseur .NET?

Nous utilisons DataContractJsonSerializer comme ceci:

var ser = new DataContractJsonSerializer(typeof(KeepTruckinResponse)); 
response = ser.ReadObject(ms) as KeepTruckinResponse; 

À ce stade, nous ne voulons pas utiliser NewtonSoft.Json

+0

Modifier votre question pour montrer hoy vous sérialisation les données. L'utilisation de 'DataContract' est généralement évitée en faveur des attributs' NewtonSoft.Json' beaucoup plus utilisés –

+0

"Evidemment, quand je désérialise JSON je ne reçois pas les propriétés de KeepTruckinCompanyWebHook parce que la façon dont ils envoient la collection est imbriquée" signifie par là. En tant que quelqu'un qui utilise Newtonsoft, je m'attendrais beaucoup à être désérialisé. –

Répondre

0

Oui, cela est possible, mais vous aurez besoin du code personnalisé pour le faire .

Il est un peu laid, mais vous pouvez créer une classe personnalisée IDataContractSurrogate désérialiser chaque objet JSON à l'intérieur du tableau company_webhooks dans un Dictionary<string, Dictionary<string, object>>, puis copiez les valeurs de la structure dictionnaire imbriqué dans une instance de votre classe KeepTruckinCompanyWebHook. Voici le code que vous avez besoin pour la mère porteuse:

class MyDataContractSurrogate : IDataContractSurrogate 
{ 
    public Type GetDataContractType(Type type) 
    { 
     if (type == typeof(KeepTruckinCompanyWebHook)) 
     { 
      return typeof(Dictionary<string, Dictionary<string, object>>); 
     } 
     return type; 
    } 

    public object GetDeserializedObject(object obj, Type targetType) 
    { 
     if (obj.GetType() == typeof(Dictionary<string, Dictionary<string, object>>) && 
      targetType == typeof(KeepTruckinCompanyWebHook)) 
     { 
      var webHook = new KeepTruckinCompanyWebHook(); 
      var outerDict = (Dictionary<string, Dictionary<string, object>>)obj; 
      var innerDict = outerDict["company_webhook"]; 

      foreach (PropertyInfo prop in GetDataMemberProperties(typeof(KeepTruckinCompanyWebHook))) 
      { 
       DataMemberAttribute att = prop.GetCustomAttribute<DataMemberAttribute>(); 

       object value; 
       if (innerDict.TryGetValue(att.Name, out value)) 
       { 
        prop.SetValue(webHook, value); 
       } 
      } 

      return webHook; 
     } 
     return obj; 
    } 

    public object GetObjectToSerialize(object obj, Type targetType) 
    { 
     if (obj.GetType() == typeof(KeepTruckinCompanyWebHook) && 
      targetType == typeof(Dictionary<string, Dictionary<string, object>>)) 
     { 
      var webHook = (KeepTruckinCompanyWebHook)obj; 
      var outerDict = new Dictionary<string, Dictionary<string, object>>(); 
      var innerDict = new Dictionary<string, object>(); 
      outerDict.Add("company_webhook", innerDict); 

      foreach (PropertyInfo prop in GetDataMemberProperties(typeof(KeepTruckinCompanyWebHook))) 
      { 
       DataMemberAttribute att = prop.GetCustomAttribute<DataMemberAttribute>(); 
       innerDict.Add(att.Name, prop.GetValue(webHook)); 
      } 

      return outerDict; 
     } 
     return obj; 
    } 

    private IEnumerable<PropertyInfo> GetDataMemberProperties(Type type) 
    { 
     return type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetCustomAttribute<DataMemberAttribute>() != null); 
    } 

    // ------- The rest of these methods do not need to be implemented ------- 
    public object GetCustomDataToExport(Type clrType, Type dataContractType) 
    { 
     throw new NotImplementedException(); 
    } 

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) 
    { 
     throw new NotImplementedException(); 
    } 

    public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes) 
    { 
     throw new NotImplementedException(); 
    } 

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) 
    { 
     throw new NotImplementedException(); 
    } 

    public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Pour utiliser le substitut, vous devrez créer une instance de DataContractJsonSerializerSettings et le transmettre à l'DataContractJsonSerializer avec les propriétés suivantes définies. Notez que puisque nous avons besoin du paramètre UseSimpleDictionaryFormat, cette solution ne fonctionnera qu'avec .Net 4.5 ou version ultérieure.

var settings = new DataContractJsonSerializerSettings(); 
settings.DataContractSurrogate = new MyDataContractSurrogate(); 
settings.KnownTypes = new List<Type> { typeof(Dictionary<string, Dictionary<string, object>>) }; 
settings.UseSimpleDictionaryFormat = true; 

Voici une démo:

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     string json = @" 
     { 
      ""company_webhooks"": [ 
      { 
       ""company_webhook"": { 
       ""id"": 42, 
       ""url"": ""https://keeptruckin.com/callbacktest/842b02"", 
       ""secret"": ""fe8b75de0a4e5898f0011faeb8c93654"", 
       ""format"": ""json"", 
       ""actions"": [ 
        ""vehicle_location_received"", 
        ""vehicle_location_updated"" 
       ], 
       ""enabled"": false 
       } 
      }, 
      { 
       ""company_webhook"": { 
       ""id"": 43, 
       ""url"": ""https://keeptruckin.com/callbacktest/a6a783"", 
       ""secret"": ""66a7368063cb21887f546c7af91be59c"", 
       ""format"": ""json"", 
       ""actions"": [ 
        ""vehicle_location_received"", 
        ""vehicle_location_updated"" 
       ], 
       ""enabled"": false 
       } 
      }, 
      { 
       ""company_webhook"": { 
       ""id"": 44, 
       ""url"": ""https://keeptruckin.com/callbacktest/53a52c"", 
       ""secret"": ""4451dc96513b3a67107466dd2c4d9589"", 
       ""format"": ""json"", 
       ""actions"": [ 
        ""vehicle_location_received"", 
        ""vehicle_location_updated"" 
       ], 
       ""enabled"": false 
       } 
      }, 
      { 
       ""company_webhook"": { 
       ""id"": 45, 
       ""url"": ""https://keeptruckin.com/callbacktest/6fb337"", 
       ""secret"": ""4177fbd88c30faaee03a4362648bd663"", 
       ""format"": ""json"", 
       ""actions"": [ 
        ""vehicle_location_received"", 
        ""vehicle_location_updated"" 
       ], 
       ""enabled"": false 
       } 
      }, 
      { 
       ""company_webhook"": { 
       ""id"": 46, 
       ""url"": ""https://keeptruckin.com/callbacktest/8cd6da"", 
       ""secret"": ""6e41817a048b009435e5102fca17db55"", 
       ""format"": ""json"", 
       ""actions"": [ 
        ""vehicle_location_received"", 
        ""vehicle_location_updated"" 
       ], 
       ""enabled"": false 
       } 
      } 
      ], 
      ""pagination"": { 
      ""per_page"": 25, 
      ""page_no"": 1, 
      ""total"": 5 
      } 
     }"; 

     var settings = new DataContractJsonSerializerSettings(); 
     settings.DataContractSurrogate = new MyDataContractSurrogate(); 
     settings.KnownTypes = new List<Type> { typeof(Dictionary<string, Dictionary<string, object>>) }; 
     settings.UseSimpleDictionaryFormat = true; 

     KeepTruckinResponse response = Deserialize<KeepTruckinResponse>(json, settings); 

     foreach (KeepTruckinCompanyWebHook wh in response.WebHooks) 
     { 
      Console.WriteLine("Id: " + wh.Id + ", Url: " + wh.Url); 
     } 
    } 

    public static T Deserialize<T>(string json, DataContractJsonSerializerSettings settings) 
    { 
     using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json))) 
     { 
      var ser = new DataContractJsonSerializer(typeof(T), settings); 
      return (T)ser.ReadObject(ms); 
     } 
    } 

    public static string Serialize(object obj, DataContractJsonSerializerSettings settings) 
    { 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      var ser = new DataContractJsonSerializer(obj.GetType(), settings); 
      ser.WriteObject(ms, obj); 
      return Encoding.UTF8.GetString(ms.ToArray()); 
     } 
    } 
} 

[DataContract] 
public class KeepTruckinResponse 
{ 
    [DataMember(Name = "company_webhooks", EmitDefaultValue = false)] 
    public KeepTruckinCompanyWebHook[] WebHooks { get; set; } 

    [DataMember(Name = "pagination", EmitDefaultValue = false)] 
    public KeepTruckinPagination Pagination { get; set; } 

    public string RawJSON { get; set; } 
} 

[DataContract] 
public class KeepTruckinPagination 
{ 
    [DataMember(Name = "per_page", EmitDefaultValue = false)] 
    public int PerPage { get; set; } 

    [DataMember(Name = "page_no", EmitDefaultValue = false)] 
    public int PageNumber { get; set; } 

    [DataMember(Name = "total", EmitDefaultValue = false)] 
    public int Total { get; set; } 
} 

[DataContract(Name = "company_webhook")] 
public class KeepTruckinCompanyWebHook 
{ 
    [DataMember(Name = "id", EmitDefaultValue = false)] 
    public int Id { get; set; } 

    [DataMember(Name = "url", EmitDefaultValue = false)] 
    public string Url { get; set; } 
} 

Sortie:

Id: 42, Url: https://keeptruckin.com/callbacktest/842b02 
Id: 43, Url: https://keeptruckin.com/callbacktest/a6a783 
Id: 44, Url: https://keeptruckin.com/callbacktest/53a52c 
Id: 45, Url: https://keeptruckin.com/callbacktest/6fb337 
Id: 46, Url: https://keeptruckin.com/callbacktest/8cd6da