Как я могу десериализовать JSON в простой словарь <string, string> в ASP.NET? - PullRequest
616 голосов
/ 30 июля 2009

У меня есть простой список ключей / значений в JSON, который отправляется обратно в ASP.NET через POST. Пример:

{ "key1": "value1", "key2": "value2"}

Я не пытаюсь десериализировать в сильно окрашенные объекты .NET

Мне просто нужен простой старый словарь (Of String, String) или какой-либо эквивалент (хеш-таблица, Dictionary (Of String, Object), старая школа StringDictionary - ад, 2-D массив строк будет работать для меня.

Я могу использовать все, что доступно в ASP.NET 3.5, а также популярный Json.NET (который я уже использую для сериализации для клиента).

По-видимому, ни одна из этих библиотек JSON не обладает такой очевидной способностью подавлять лоб - они полностью сосредоточены на десериализации на основе отражений с помощью сильных контрактов.

Есть идеи?

Ограничения:

  1. Я не хочу реализовывать свой собственный анализатор JSON
  2. Пока не могу использовать ASP.NET 4.0
  3. Предпочитает держаться подальше от устаревшего устаревшего класса ASP.NET для JSON

Ответы [ 19 ]

809 голосов
/ 31 июля 2009

Json.NET делает это ...

string json = @"{""key1"":""value1"",""key2"":""value2""}";

var values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);

Дополнительные примеры: Сериализация коллекций с помощью Json.NET

96 голосов
/ 29 января 2010

Я обнаружил, что .NET имеет встроенный способ преобразования строки JSON в Dictionary<String, Object> через тип System.Web.Script.Serialization.JavaScriptSerializer в сборке 3.5 System.Web.Extensions. Используйте метод DeserializeObject(String).

Я наткнулся на это, когда делал пост ajax (через jquery) типа контента 'application / json' для статического .net Page Method и увидел, что метод (у которого был один параметр типа Object) магическим образом получил этот словарь.

52 голосов
/ 21 апреля 2011

Для тех, кто ищет в интернете и наткнулся на этот пост, я написал пост в блоге о том, как использовать класс JavaScriptSerializer.

Подробнее ... http://procbits.com/2011/04/21/quick-json-serializationdeserialization-in-c/

Вот пример:

var json = "{\"id\":\"13\", \"value\": true}";
var jss = new JavaScriptSerializer();
var table = jss.Deserialize<dynamic>(json);
Console.WriteLine(table["id"]);
Console.WriteLine(table["value"]);
40 голосов
/ 12 января 2012

Пытался не использовать какую-либо внешнюю реализацию JSON, поэтому я десериализовался так:

string json = "{\"id\":\"13\", \"value\": true}";

var serializer = new JavaScriptSerializer(); //using System.Web.Script.Serialization;

Dictionary<string, string> values = serializer.Deserialize<Dictionary<string, string>>(json);
34 голосов
/ 25 июля 2011

У меня была такая же проблема, поэтому я написал это сам. Это решение отличается от других ответов, потому что оно может десериализоваться на нескольких уровнях.

Просто отправьте строку JSON в функцию deserializeToDictionary , которая будет возвращать не строго типизированный Dictionary<string, object> объект.

Старый код

private Dictionary<string, object> deserializeToDictionary(string jo)
{
    var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
    var values2 = new Dictionary<string, object>();
    foreach (KeyValuePair<string, object> d in values)
    {
        // if (d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject"))
        if (d.Value is JObject)
        {
            values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
        }
        else
        {
            values2.Add(d.Key, d.Value);
        }
    }
    return values2;
}

Пример. Возвращает Dictionary<string, object> объект ответа JSON Facebook.

Test

private void button1_Click(object sender, EventArgs e)
{
    string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\",  hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}";
    Dictionary<string, object> values = deserializeToDictionary(responsestring);
}

Примечание: родной город далее опустошается в Dictionary<string, object> объект.

Обновление

Мой старый ответ прекрасно работает, если в строке JSON нет массива. Это еще раз десериализовать в List<object>, если элемент является массивом.

Просто отправьте строку JSON в функцию deserializeToDictionaryOrList , которая будет возвращать не строго типизированный Dictionary<string, object> объект или List<object>.

private static object deserializeToDictionaryOrList(string jo,bool isArray=false)
{
    if (!isArray)
    {
        isArray = jo.Substring(0, 1) == "[";
    }
    if (!isArray)
    {
        var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
        var values2 = new Dictionary<string, object>();
        foreach (KeyValuePair<string, object> d in values)
        {
            if (d.Value is JObject)
            {
                values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
            }
            else if (d.Value is JArray)
            {
                values2.Add(d.Key, deserializeToDictionary(d.Value.ToString(), true));
            }
            else
            {
                values2.Add(d.Key, d.Value);
            }
        }
        return values2;
    }else
    {
        var values = JsonConvert.DeserializeObject<List<object>>(jo);
        var values2 = new List<object>();
        foreach (var d in values)
        {
            if (d is JObject)
            {
                values2.Add(deserializeToDictionary(d.ToString()));
            }
            else if (d is JArray)
            {
                values2.Add(deserializeToDictionary(d.ToString(), true));
            }
            else
            {
                values2.Add(d);
            }
        }
        return values2;
    }
}
16 голосов
/ 02 ноября 2012

Если вы предпочитаете легкий подход без ссылок, возможно, этот фрагмент кода, который я только что написал, сработает (хотя я не могу на 100% гарантировать надежность).

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

public Dictionary<string, object> ParseJSON(string json)
{
    int end;
    return ParseJSON(json, 0, out end);
}
private Dictionary<string, object> ParseJSON(string json, int start, out int end)
{
    Dictionary<string, object> dict = new Dictionary<string, object>();
    bool escbegin = false;
    bool escend = false;
    bool inquotes = false;
    string key = null;
    int cend;
    StringBuilder sb = new StringBuilder();
    Dictionary<string, object> child = null;
    List<object> arraylist = null;
    Regex regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
    int autoKey = 0;
    for (int i = start; i < json.Length; i++)
    {
        char c = json[i];
        if (c == '\\') escbegin = !escbegin;
        if (!escbegin)
        {
            if (c == '"')
            {
                inquotes = !inquotes;
                if (!inquotes && arraylist != null)
                {
                    arraylist.Add(DecodeString(regex, sb.ToString()));
                    sb.Length = 0;
                }
                continue;
            }
            if (!inquotes)
            {
                switch (c)
                {
                    case '{':
                        if (i != start)
                        {
                            child = ParseJSON(json, i, out cend);
                            if (arraylist != null) arraylist.Add(child);
                            else
                            {
                                dict.Add(key, child);
                                key = null;
                            }
                            i = cend;
                        }
                        continue;
                    case '}':
                        end = i;
                        if (key != null)
                        {
                            if (arraylist != null) dict.Add(key, arraylist);
                            else dict.Add(key, DecodeString(regex, sb.ToString()));
                        }
                        return dict;
                    case '[':
                        arraylist = new List<object>();
                        continue;
                    case ']':
                        if (key == null)
                        {
                            key = "array" + autoKey.ToString();
                            autoKey++;
                        }
                        if (arraylist != null && sb.Length > 0)
                        {
                            arraylist.Add(sb.ToString());
                            sb.Length = 0;
                        }
                        dict.Add(key, arraylist);
                        arraylist = null;
                        key = null;
                        continue;
                    case ',':
                        if (arraylist == null && key != null)
                        {
                            dict.Add(key, DecodeString(regex, sb.ToString()));
                            key = null;
                            sb.Length = 0;
                        }
                        if (arraylist != null && sb.Length > 0)
                        {
                            arraylist.Add(sb.ToString());
                            sb.Length = 0;
                        }
                       continue;
                    case ':':
                        key = DecodeString(regex, sb.ToString());
                        sb.Length = 0;
                        continue;
                }
            }
        }
        sb.Append(c);
        if (escend) escbegin = false;
        if (escbegin) escend = true;
        else escend = false;
    }
    end = json.Length - 1;
    return dict; //theoretically shouldn't ever get here
}
private string DecodeString(Regex regex, string str)
{
    return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber))));
}

[Я понимаю, что это нарушает ОП № 1, но технически вы не написали это, я сделал]

14 голосов
/ 11 августа 2016

Мне просто нужно было разобрать вложенный словарь, например

{
    "x": {
        "a": 1,
        "b": 2,
        "c": 3
    }
}

, где JsonConvert.DeserializeObject не помогает. Я нашел следующий подход:

var dict = JObject.Parse(json).SelectToken("x").ToObject<Dictionary<string, int>>();

SelectToken позволяет перейти к нужному полю. Вы даже можете указать путь, например "x.y.z", чтобы пройти дальше в объект JSON.

5 голосов
/ 03 марта 2015

Я добавил код, представленный здесь jSnake04 и Dasun. Я добавил код для создания списков объектов из JArray экземпляров. Он имеет двухстороннюю рекурсию, но, поскольку он функционирует на фиксированной модели с конечным деревом, нет риска переполнения стека, если данные не являются массивными.

/// <summary>
/// Deserialize the given JSON string data (<paramref name="data"/>) into a
///   dictionary.
/// </summary>
/// <param name="data">JSON string.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(string data)
{
    var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);

    return DeserializeData(values);
}

/// <summary>
/// Deserialize the given JSON object (<paramref name="data"/>) into a dictionary.
/// </summary>
/// <param name="data">JSON object.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(JObject data)
{
    var dict = data.ToObject<Dictionary<String, Object>>();

    return DeserializeData(dict);
}

/// <summary>
/// Deserialize any elements of the given data dictionary (<paramref name="data"/>) 
///   that are JSON object or JSON arrays into dictionaries or lists respectively.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(IDictionary<string, object> data)
{
    foreach (var key in data.Keys.ToArray()) 
    {
        var value = data[key];

        if (value is JObject)
            data[key] = DeserializeData(value as JObject);

        if (value is JArray)
            data[key] = DeserializeData(value as JArray);
    }

    return data;
}

/// <summary>
/// Deserialize the given JSON array (<paramref name="data"/>) into a list.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized list.</returns>
private IList<Object> DeserializeData(JArray data)
{
    var list = data.ToObject<List<Object>>();

    for (int i = 0; i < list.Count; i++)
    {
        var value = list[i];

        if (value is JObject)
            list[i] = DeserializeData(value as JObject);

        if (value is JArray)
            list[i] = DeserializeData(value as JArray);
    }

    return list;
}
5 голосов
/ 30 июля 2009

Редактировать: Это работает, но принятый ответ с использованием Json.NET гораздо проще. Оставьте это на тот случай, если кому-то нужен код только BCL.

Он не поддерживается платформой .NET из коробки. Яркий недосмотр - не всем нужно десериализовать объекты с именованными свойствами. Так что я закончил кататься самостоятельно:

<Serializable()> Public Class StringStringDictionary
    Implements ISerializable
    Public dict As System.Collections.Generic.Dictionary(Of String, String)
    Public Sub New()
        dict = New System.Collections.Generic.Dictionary(Of String, String)
    End Sub
    Protected Sub New(info As SerializationInfo, _
          context As StreamingContext)
        dict = New System.Collections.Generic.Dictionary(Of String, String)
        For Each entry As SerializationEntry In info
            dict.Add(entry.Name, DirectCast(entry.Value, String))
        Next
    End Sub
    Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
        For Each key As String in dict.Keys
            info.AddValue(key, dict.Item(key))
        Next
    End Sub
End Class

Вызывается с:

string MyJsonString = "{ \"key1\": \"value1\", \"key2\": \"value2\"}";
System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs = new
  System.Runtime.Serialization.Json.DataContractJsonSerializer(
    typeof(StringStringDictionary));
System.IO.MemoryStream ms = new
  System.IO.MemoryStream(Encoding.UTF8.GetBytes(MyJsonString));
StringStringDictionary myfields = (StringStringDictionary)dcjs.ReadObject(ms);
Response.Write("Value of key2: " + myfields.dict["key2"]);

Извините за смесь C # и VB.NET ...

4 голосов
/ 07 мая 2014

Я добавил проверку на нулевые значения в JSON для другого ответа

У меня была такая же проблема, поэтому я написал это сам. Это решение отличается от других ответов, потому что он может десериализовать в несколько уровней.

Просто отправьте строку json в deserializeToDictionary и используйте его вернет не типизированный Dictionary<string, object> объект.

private Dictionary<string, object> deserializeToDictionary(string jo)
{
    var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
    var values2 = new Dictionary<string, object>();
    foreach (KeyValuePair<string, object> d in values)
    {
        if (d.Value != null && d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject"))
        {
            values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
        }
        else
        {
            values2.Add(d.Key, d.Value);
        }
    }
    return values2;
}

Пример: это вернет Dictionary<string, object> объект Facebook Ответ JSON.

private void button1_Click(object sender, EventArgs e)
{
    string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera
        Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\",
        hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}";
    Dictionary<string, object> values = deserializeToDictionary(responsestring);
}

Примечание: родной город далее десериализуется в Dictionary<string, object> объект.

...