1
votes

JsonConvert.DeserializeObject ne convertit pas un objet de réponse à partir de JSON comme prévu

Je crée un wrapper ActiveCampaign V1.1 pour C # .NET et crée une classe qui répertorie les ContactLists en utilisant ( https://www.activecampaign.com/api/example.php?call=list_list )

L'objet de réponse renvoyé après JsonConvert.DeserializeObject ( JSON) a des propriétés non-list remplies, mais la partie liste du JSON n'est pas convertie.

J'ai essayé les implémentations BasicListResponse suivantes: p >

{
    "0": {
        "id": "1",
        "name": "xxxxx xxxxxx xxxxxxx",
        "cdate": "2019-10-27 22:43:23",
        "private": "0",
        "userid": "1",
        "subscriber_count": 1
    },
    "1": {
        "id": "2",
        "name": "yyyyy yyyyy yyyyy",
        "cdate": "2019-10-27 22:44:03",
        "private": "0",
        "userid": "1",
        "subscriber_count": 0
    },
    "result_code": 1,
    "result_message": "Success: Something is returned",
    "result_output": "json"
}

J'ai également essayé d'utiliser json2csharp ou VS> Coller spécial mais la sortie a des classes numérotées plutôt qu'une liste d'objets.

La réponse JSON est la suivante:

public class Result
{
    [JsonProperty("result_code")]
    public int ResultCode { get; set; }

    [JsonProperty("result_message")]
    public string ResultMessage { get; set; }

    [JsonProperty("result_output")]
    public string ResultOutput { get; set; }
}

public class BasicListResponse : Result
{      
    public Dictionary<string, BasicList> list { get; set; }
}

public class BasicList
{
    [JsonProperty("id")]
    public string Id { get; set; }

    [Required]
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("cdate")]
    public DateTime CreatedOn { get; set; }

    [JsonProperty("private")]
    public bool Private { get; set; }

    [JsonProperty("userid")]
    public string UserId { get; set; }

    [JsonProperty("subscriber_count")]
    public int SubscriberCount { get; set; }
}

J'ai extrait le Dictionary dans le wrapper mais la liste est toujours NULL.

Si je re-sérialise la BasicListResponse , les résultats sont les suivants s

{"list": null, "result_code": 1, "result_message": "Success: Quelque chose est retourné", "result_output": "json"} p>

Je m'attends à ce que la BasicListResponse soit utilisée comme un objet racine contenant un List / Array avec trois propriétés de chaîne result_ * .

I apprécier toute aide pour résoudre ce problème.


6 commentaires

L'objet JSON ne contient pas de liste . Peut-être avez-vous besoin de cette question ?


app.quicktype.io/#l=cs&r=json2csharp essayez ceci pour vous en sortir structure de classe correspondant à votre JSON


Est-ce que cela répond à votre question? Gestion des membres supplémentaires lors de la désérialisation avec Json.net


Peut-être que cela aide: dotnetfiddle.net/eSLWpe


Essayez de désérialiser directement dans Dictionary .


@john - cette question était également utile. @ rahul-sharma - Votre solution fonctionnait mais j'ai opté pour @ brian-rodgers parce que j'avais tendance à convertir directement en List plutôt qu'en dynamique


3 Réponses :


0
votes

Ce n'est pas la solution la plus élégante, mais vous pouvez structurer vos classes comme ceci:

result_code=1,result_message=Success: Something is returned,result_output=json
Id=1,Name=xxxxx xxxxxx xxxxxxx,CDate=27/10/2019 10:43:23 PM,Private=0,UserId=1,SubscriberCount=1
Id=2,Name=yyyyy yyyyy yyyyy,CDate=27/10/2019 10:44:03 PM,Private=0,UserId=1,SubscriberCount=0

Ensuite, vous pouvez désérialiser votre json et mapper vos IDictionary Items code> à un IEnumerable . Notez que JsonExtensionData doit être IDictionary dans ce cas.

var deserializedJson = JsonConvert.DeserializeObject<Results>(json);

var results = deserializedJson
    .Items
    .Select(entry => new Result
    {
        Id = (long)entry.Value["id"],
        Name = (string)entry.Value["name"],
        Cdate = DateTime.TryParse((string)entry.Value["cdate"], out var cdate) ? cdate : DateTime.MinValue,
        Private = (long)entry.Value["private"],
        UserId = (long)entry.Value["userid"],
        SubscriberCount = (long)entry.Value["subscriber_count"]
    });

Console.WriteLine($"result_code={deserializedJson.ResultCode},result_message={deserializedJson.ResultMessage},result_output={deserializedJson.ResultOutput}");
foreach (var result in results)
{
    Console.WriteLine(result.ToString());
}

Sortie :

public class Results
{
    [JsonExtensionData]
    public IDictionary<string, JToken> Items;

    [JsonProperty("result_code")]
    public long ResultCode { get; set; }

    [JsonProperty("result_message")]
    public string ResultMessage { get; set; }

    [JsonProperty("result_output")]
    public string ResultOutput { get; set; }
}

public class Result
{
    public long Id { get; set; }

    public string Name { get; set; }

    public DateTime Cdate { get; set; }

    public long Private { get; set; }

    public long UserId { get; set; }

    public long SubscriberCount { get; set; }

    public override string ToString()
    {
        return $"Id={Id},Name={Name},CDate={Cdate.ToString()},Private={Private},UserId={UserId},SubscriberCount={SubscriberCount}";
    }
}


0 commentaires

-1
votes

Essayez

"list":{
    "0": {
        "id": "1",
        "name": "xxxxx xxxxxx xxxxxxx",
        "cdate": "2019-10-27 22:43:23",
        "private": "0",
        "userid": "1",
        "subscriber_count": 1
    },
    "1": {
        "id": "2",
        "name": "yyyyy yyyyy yyyyy",
        "cdate": "2019-10-27 22:44:03",
        "private": "0",
        "userid": "1",
        "subscriber_count": 0
    },
    "result_code": 1,
    "result_message": "Success: Something is returned",
    "result_output": "json"
}


2 commentaires

Cela ne résout pas le problème du PO. Le JSON provient d'un tiers.


@shan, n'emprunterait pas le chemin de manipulation JSON pour résoudre le problème. Le JSON reçu est fixe.



3
votes

Votre JSON représente essentiellement un dictionnaire de paires string - BasicList , mélangé avec d'autres propriétés concernant le résultat global. Ce format rend le travail plus difficile. (Il aurait été préférable que les données du dictionnaire se trouvent dans un objet enfant dans le JSON.)

Le moyen le plus simple de gérer cette situation est de tirer parti de " Extension Data ".

Voici ce que vous devez faire:

  1. Créez une propriété privée Dictionary dans votre classe BasicListResponse et marquez-la avec l'attribut [JsonExtensionData] . Cela capturera les données du dictionnaire lors de la désérialisation.
  2. Changez votre propriété list en une List au lieu d'un Dictionary . (Je le renommerais également avec une capitalisation appropriée pour être cohérent avec vos autres propriétés.)
  3. Ajoutez une méthode OnDeserialized privée comme indiqué ci-dessous pour remplir la List à partir du dictionnaire d'extension à la fin du processus de désérialisation.

Donc, votre classe BasicListResponse devrait ressembler à ceci:

var result = JsonConvert.DeserializeObject<BasicListResponse>(json);

Il y a un autre petit problème que nous devons résoudre: dans votre classe BasicList vous avez défini la propriété Private comme bool , mais dans le JSON, il s'agit d'une chaîne contenant un nombre. Cela entraînera l'échec de la désérialisation en raison de types incompatibles. Pour que cela fonctionne, vous pouvez soit changer Private en une chaîne, puis gérer l'interprétation de la valeur ailleurs dans votre code, ou vous pouvez faire quelque chose comme ceci:

public class BasicList
{
    ...

    [JsonProperty("private")]
    private string PrivateAsString { get; set; }

    [JsonIgnore]
    public bool Private
    {
        get { return PrivateAsString != "0"; }
        set { PrivateAsString = value ? "1" : "0"; }
    }

    ...
}

Avec ces changements, vous pouvez désérialiser votre classe BasicListResponse et tout devrait fonctionner correctement.

public class BasicListResponse : Result
{
    public List<BasicList> List { get; set; }

    [JsonExtensionData]
    private Dictionary<string, JToken> Data { get; set; }

    [OnDeserialized]
    private void OnDeserialized(StreamingContext context)
    {
        List = Data?.OrderBy(kvp => kvp.Key)
                    .Select(kvp => kvp.Value.ToObject<BasicList>())
                    .ToList();
    }
}

Démo de travail ici: https://dotnetfiddle.net/9MmSuG


3 commentaires

Rodgers - je vais y aller


Rodgers, la solution a fonctionné. Merci pour l'aide. »[JsonExtensionData]` va être un excellent outil car je travaille avec beaucoup de JSON qui ne suivent pas une bonne structure.


Aucun problème; Je suis content que vous ayez trouvé la solution utile.