Сериализировать List‹KeyValuePair‹string, string›› как JSON

Я очень новичок в JSON, пожалуйста, помогите!

Я пытаюсь сериализовать List<KeyValuePair<string, string>> как JSON

В настоящее время:

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

Ожидал:

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

Я сослался на несколько примеров из этого и это.

Это мой 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;
    }
}

Я вызываю его из метода WebService, подобного этому

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

person maryhadalittlelamb    schedule 06.01.2017    source источник
comment
Попробуйте изменить «objectType == typeof(List‹KeyValuePair‹object, object››);» на «objectType == typeof(List‹KeyValuePair‹string, string››);» в методе CanConvert   -  person Ralf Bönning    schedule 06.01.2017
comment
Один вопрос - почему вы используете список KeyValuePairs вместо словаря?   -  person Sergey Berezovskiy    schedule 06.01.2017
comment
@СергейБерезовский ты прав! Думаю, я заблудился, когда гуглил, что использовать, и в итоге все усложнил. Благодарю вас!   -  person maryhadalittlelamb    schedule 09.01.2017


Ответы (2)


Вы можете использовать Newtonsoft и словарь:

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

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

Результат:

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

Изменить

Спасибо @Сергею Березовскому за информацию.

В настоящее время вы используете Newtonsoft, поэтому просто измените List<KeyValuePair<object, object>> на Dictionary<object,object> и используйте метод сериализации и десериализации из пакета.

person OrcusZ    schedule 06.01.2017
comment
Так что ему просто нужно изменить List‹KeyValuePair‹object, object›› на Dictionnary‹object,object›. я отредактирую свой ответ - person OrcusZ; 06.01.2017
comment
Об этом я и спросил его в комментариях. Не всегда возможно изменить список KeyValuePairs на словарь. Пример — вы можете использовать KVP для передачи ключей-значений в качестве альтернативы Tuple или создания класса. И у вас может быть много пар ключ-значение с одним и тем же ключом. Что не так со словарем. - person Sergey Berezovskiy; 06.01.2017
comment
В своем методе создания он меняет, если ключ уже существует, поэтому я думаю, что мы больше находимся в ситуации, когда нужен словарь, но вы совершенно правы, в некоторых случаях такой список может быть полезен :) - person OrcusZ; 06.01.2017
comment
@OrcusZ спасибо за помощь! Я удалил List‹KeyValuePair‹string, string›› просто Dictionary‹string, string›, и сериализация просто заработала. - person maryhadalittlelamb; 09.01.2017
comment
так легко, когда вы это знаете. Благодарю. этот ответ был бы очень полезен, если бы объяснил, почему... чем пара ключ-значение отличается от словаря, чтобы объяснить эту разницу в поведении сериализации? - person Cee McSharpface; 03.02.2018
comment
Я не согласен. List‹KeyValuePair‹object, object›› поддерживает порядок вставки, а Dictionary — нет. - person Kamaal; 18.11.2020

Поэтому я не хотел использовать что-либо, кроме собственного С#, для решения аналогичной проблемы, и для справки я использовал .net 4, jquery 3.2.1 и основу 1.2.0.

Моя проблема заключалась в том, что List<KeyValuePair<...>> будет обрабатываться из контроллера в модель магистрали, но когда я сохранил эту модель, контроллер не смог связать 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);
}

захват сети:

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

Но даже если это правильно установило SomeList в резервной модели model.js, попытка сохранить модель без каких-либо изменений в ней привела бы к тому, что объект привязки SomeModel имел бы ту же длину, что и параметры в теле запроса, но все ключи и значения были нулевыми:

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

Единственное, что я смог найти, это то, что KeyValuePair является структурой, а не чем-то, что может быть создано таким образом. В итоге я сделал следующее:

  • Добавьте где-нибудь оболочку модели, содержащую поля ключей и значений:

    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;
        }
    }
    
  • Настройте модель класса привязки, чтобы принять ваш пользовательский объект-оболочку.

    public class SomeModel
    {
        public List<KeyValuePairWrapper> KeyValuePairList{ get; set }; 
    }
    
  • Получить некоторые данные json из контроллера

    [HttpGet]
    SomeControllerMethod() {
        SomeModel someModel = new SomeModel();
        someModel.KeyValuePairList = GetListSortedAlphabetically();
        return this.Json(someModel, JsonBehavior.AllowGet);
    }
    
  • Сделайте что-нибудь позже, возможно, вызывается model.save(null,...)

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