web-dev-qa-db-fra.com

Sérialiser la liste <KeyValuePair <chaîne, chaîne >> au format JSON

Je suis très nouveau avec JSON, aidez-moi!

J'essaie de sérialiser un List<KeyValuePair<string, string>> comme JSON

Actuellement:

[{"Key":"MyKey 1","Value":"MyValue 1"},{"Key":"MyKey 2","Value":"MyValue 2"}]

Attendu:

[{"MyKey 1":"MyValue 1"},{"MyKey 2":"MyValue 2"}]

J'ai fait référence à quelques exemples de this et this .

Ceci est mon KeyValuePairJsonConverter: JsonConverter

public class KeyValuePairJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        List<KeyValuePair<object, object>> list = value as List<KeyValuePair<object, object>>;
        writer.WriteStartArray();
        foreach (var item in list)
        {
            writer.WriteStartObject();
            writer.WritePropertyName(item.Key.ToString());
            writer.WriteValue(item.Value.ToString());
            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<KeyValuePair<object, object>>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        var target = Create(objectType, jsonObject);
        serializer.Populate(jsonObject.CreateReader(), target);
        return target;
    }

    private object Create(Type objectType, JObject jsonObject)
    {
        if (FieldExists("Key", jsonObject))
        {
            return jsonObject["Key"].ToString();
        }

        if (FieldExists("Value", jsonObject))
        {
            return jsonObject["Value"].ToString();
        }
        return null;
    }

    private bool FieldExists(string fieldName, JObject jsonObject)
    {
        return jsonObject[fieldName] != null;
    }
}

Je l'appelle à partir d'une méthode WebService comme celle-ci

List<KeyValuePair<string, string>> valuesList = new List<KeyValuePair<string, string>>();
Dictionary<string, string> valuesDict = SomeDictionaryMethod();

foreach(KeyValuePair<string, string> keyValue in valuesDict)
{
    valuesList.Add(keyValue);
}

JsonSerializerSettings jsonSettings = new JsonSerializerSettings { Converters = new [] {new KeyValuePairJsonConverter()} };
string valuesJson = JsonConvert.SerializeObject(valuesList, jsonSettings);
17
maryhadalittlelamb

Vous pouvez utiliser Newtonsoft et dictionnaire:

    var dict = new Dictionary<int, string>();
    dict.Add(1, "one");
    dict.Add(2, "two");

    var output = Newtonsoft.Json.JsonConvert.SerializeObject(dict);

La sortie est:

{"1":"one","2":"two"}

Modifier

Merci à @ Sergey Berezovskiy pour l'information.

Vous utilisez actuellement Newtonsoft, alors changez simplement votre List<KeyValuePair<object, object>> à Dictionary<object,object> et utilisez la méthode serialize et deserialize du package.

25
OrcusZ

Je ne voulais donc pas utiliser autre chose que du c # natif pour résoudre un problème similaire et pour référence, j'utilisais .net 4, jquery 3.2.1 et backbone 1.2.0.

Mon problème était que le List<KeyValuePair<...>> serait transformé hors du contrôleur en un modèle de base, mais lorsque j'ai enregistré ce modèle, le contrôleur n'a pas pu lier List.

public class SomeModel {
    List<KeyValuePair<int, String>> SomeList { get; set; }
}

[HttpGet]
SomeControllerMethod() {
    SomeModel someModel = new SomeModel();
    someModel.SomeList = GetListSortedAlphabetically();
    return this.Json(someModel, JsonBehavior.AllowGet);
}

capture réseau:

"SomeList":[{"Key":13,"Value":"aaab"},{"Key":248,"Value":"aaac"}]

Mais même si cela définissait SomeList correctement dans le dossier model.js en essayant d'enregistrer le modèle sans aucune modification, l'objet SomeModel de liaison aurait la même longueur que les paramètres dans le corps de la demande, mais toutes les clés et valeurs étaient nulles:

[HttpPut]
SomeControllerMethod([FromBody] SomeModel){
    SomeModel.SomeList; // Count = 2, all keys and values null.
}

La seule chose que j'ai pu trouver est que KeyValuePair est une structure et non quelque chose qui peut être instancié de cette manière. J'ai fini par faire ce qui suit:

  • Ajoutez un wrapper de modèle quelque part qui contient des champs de clé et de valeur:

    public class KeyValuePairWrapper {
        public int Key { get; set; }
        public String Value { get; set; }
    
        //default constructor will be required for binding, the Web.MVC binder will invoke this and set the Key and Value accordingly.
        public KeyValuePairWrapper() { }
    
        //a convenience method which allows you to set the values while sorting
        public KeyValuePairWrapper(int key, String value)
        {
            Key = key;
            Value = value;
        }
    }
    
  • Configurez votre modèle de classe de liaison pour accepter votre objet wrapper personnalisé.

    public class SomeModel
    {
        public List<KeyValuePairWrapper> KeyValuePairList{ get; set }; 
    }
    
  • Extraire des données json d'un contrôleur

    [HttpGet]
    SomeControllerMethod() {
        SomeModel someModel = new SomeModel();
        someModel.KeyValuePairList = GetListSortedAlphabetically();
        return this.Json(someModel, JsonBehavior.AllowGet);
    }
    
  • Faites quelque chose plus tard, peut-être que model.save (null, ...) est invoqué

    [HttpPut]
    SomeControllerMethod([FromBody] SomeModel){
        SomeModel.KeyValuePairList ; // Count = 2, all keys and values are correct.
    }
    
2
steven87vt