ASP.NET'te basit bir Sözlük <string, string> JSON serisini nasıl kaldırabilirim?


682

JSON POST aracılığıyla ASP.NET'e geri gönderilir basit bir anahtar / değer listesi var. Misal:

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

GÜÇLÜ ÇEŞİTLİ.

Sadece düz eski Sözlük (String, String) veya bazı eşdeğer (karma tablo, Sözlük (String, Object), old-StringDDictionary - cehennem, cehennem, dizelerin bir 2-D dizi benim için işe yarayacak.

ASP.NET 3.5'te bulunan her şeyi ve popüler Json.NET'i (zaten istemciye serileştirme için kullanıyorum ) kullanabilirim.

Görünüşe göre bu JSON kütüphanelerinin hiçbiri bu alnı tokatlayan bariz kabiliyete sahip değil - tamamen güçlü sözleşmeler yoluyla yansımaya dayalı serileştirmeye odaklanmış durumdalar.

Herhangi bir fikir?

Sınırlamalar:

  1. Kendi JSON ayrıştırıcımı uygulamak istemiyorum
  2. Henüz ASP.NET 4.0 kullanılamıyor
  3. JSON için eski, kullanımdan kaldırılmış ASP.NET sınıfından uzak durmayı tercih ederim

1
re: sınırlama 3, JavaScriptSerizlizerASP.NET MVC'de kullanılır ve artık kullanımdan kaldırılmamıştır.
bdukes

17
bir json dizesini birçok farklı yığın akışı üzerinden çevirmeden kolayca kullanabileceğim bir şeye dönüştürmenin basit bir yolunu bulmak inanılmazdı. Diğer dillerde çok kolay, ancak Java ve C # hayatı zorlaştırmak için kendi yollarından çıkıyor gibi görünüyor.
user299709

Yanıtlar:


893

Json.NET bunu yapar ...

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

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

Daha fazla örnek: Koleksiyonları Json.NET ile Serileştirme


9
Değerleriniz tamsayı olduğunda da çalışır mı? Otomatik olarak 'dizelere' mi dökülürler?
Highmastdon

58
@Highmastdon Hayır değil. Bir sözlüğe serileştirmenin en iyi yolunu dynamic, değerler için tür olarak kullanmaktır :JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json);
Erik Schierboom

1
Bu sayfada çok karışık bir anahtar / değer çifti ile birkaç cevap denedim ve çalıştığım tek kişi JSON.NET oldu.
bnieland

15
Eğer json anahtar / değer çiftleri bir dizi kullanıyorsanız [{key: "a", value: "1"}, {key: "b", value:"2"}]çalışmıyor Böyle bir şey yapmak zorunda:var dict = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(json);
Adrian

8
Değerler iç içe nesnelerse de çalışmaz, çünkü json.net bunları JObjects olarak oluşturur
Kugel

100

Ben discover .NET bir bir içine JSON dizesi atmak şekilde inşa etti yaptılar Dictionary<String, Object>aracılığıyla System.Web.Script.Serialization.JavaScriptSerializer3.5'de tip System.Web.Extensionsmontaj. Yöntemi kullanın DeserializeObject(String).

Ben statik bir .net Sayfa Yöntemi içerik türü 'application / json' ajax yazı (jquery aracılığıyla) yaparken tökezledi ve yöntem (tür tek bir parametre vardı) gördüm Object ) sihirli bu Sözlük aldı .


5
ancak yerleşik javascriptserializer json.net daha üşüşücüdür, bu çözüm daha iyidir. Örneğin, javascriptseralizer boş dizeler yerine null döndürür ve nullable özellikleri için hiç çalışmaz, vb.
pilavdzice

1
@pilavdzice MS'in standart olmayan tarih biçimini kabul ettiği için tarihleri ​​ayrıştırmaya çalışırken sahip olduğunuz eğlenceden bahsetmiyoruz.
Temel

16
Hızlı kod örneği: var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();arkasındanDictionary<string, object> dict = (Dictionary<string, object>)jsSerializer.DeserializeObject(jsonString);
Nate Cook

6
Nate Cook'un basit bir durumda örneğinin avantajı, harici DLL'lere ihtiyaç duymamaktır. Yalnızca .Net çerçevesine güvenebilen bağımsız bir konsoldan bir API'ye erişiyorum.
Nick.T

@pilavdzice Bununla ilgili daha ayrıntılı bilgi verebilir misiniz? Ben "boş dizeleri yerine null dönüş" şey çoğaltamaz, bana boş bir dize değeri verdiSomeData: ""
jrh

51

İnternette arama yapan ve bu gönderiyi tökezleyenler için, JavaScriptSerializer sınıfının nasıl kullanılacağı hakkında bir blog yazısı yazdım.

Daha fazla bilgi ... http://procbits.com/2011/04/21/quick-json-serializationdeserialization-in-c/

İşte bir örnek:

var json = "{\"id\":\"13\", \"value\": true}";
var jss = new JavaScriptSerializer();
var table = jss.Deserialize<dynamic>(json);
Console.WriteLine(table["id"]);
Console.WriteLine(table["value"]);

hm, çözümünüzü denedim ... Böyle {"id": "13", "değer": true} gibi json var ve benim için sadece Sözlük <dinamik> çözüm çalışır
Marko

ok Sorunun nerede olduğunu buldum ... düzgün bir şekilde serisini kaldırmak için sözlük bildiriminden sonra [] eklemeniz gerekiyor ... Blog yazılarınıza da yorum ekliyorum ... şerefe;)
Marko

Cevabınızı, veri kümenizi yansıtacak şekilde güncelledim. Dinamik ile iyi çalışır.
JP Richardson

Ben sadece biraz daha esnek ve Silverlight destekleyen başka bir JSON ayrıştırıcı yazdı: procbits.com/2011/08/11/…
JP Richardson

41

Herhangi bir harici JSON uygulaması kullanmaya çalıştım, bu yüzden bu şekilde serisini kaldırma:

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

6
System.Web.Script kullanmak için referans System.Web.Extensions ekleyin
Patrick Cullen

1
Bu cevabı en çok sevdim çünkü basit ve .NET kullanıyor System.Web.Script.Serialization. Sadece çalışıyor. Hatta "geçersiz" JSON gibi kullanabildim string json = "{'id':13, 'value': true}";.
styfle

Meraktan, OrdinalIgnoreCase sözlüğünün serisini kaldırmanın tek bir yolu var mı?
batbaatar

38

Aynı problemim vardı, bu yüzden bunu kendim yazdım. Bu çözüm diğer cevaplardan farklıdır çünkü çoklu seviyelerde seriyi kaldırabilir.

Sadece JSON dizesini deserializeToDictionary işlevine gönderin , güçlü yazılmayan bir Dictionary<string, object>nesne döndürür .

Eski kod

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

Örn: Bu Dictionary<string, object>, bir Facebook JSON yanıtının nesnesini döndürür .

Ölçek

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

Not: memleketi bir Dictionary<string, object> nesneye daha da deserilize .

Güncelleme

JSON dizesinde dizi yoksa eski cevabım harika çalışıyor. Bu, birList<object>Bir öğe bir dizi ise, .

Sadece deserializeToDictionaryOrList işlevine bir JSON dizesi gönderin, güçlü yazılmamış bir Dictionary<string, object>nesne döndürür veya 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;
    }
}

@Jordan işaret ettiğiniz için teşekkürler, bu kodda bazı değişiklikler yaptım ama şimdi yok. Bu kod JArray nesnelerini işlemez, kodu aldıktan sonra güncelleyeceğim.
Dasun

1
Problem değil. Sadece bahsettiğim için, isve asoperatörler hakkında bilgi edinmek bana çok yardımcı oldu ve kendi kodumu basitleştirdi.
Ürdün

Çalışır, ancak verimli değildir, çünkü ToString'i çağırır ve sonra tekrar Deserialize eder. Aşağıdaki Falko'nun cevabına bakın. Kaynak dizginin yalnızca bir kez serisini kaldırır.
Sergei Zinovyev

1
Falko'nun cevabı sadece veri yapısını önceden biliyorsanız çalışır. Bu çözüm herhangi bir JSON dizesi için kullanılabilir.
Dasun

16

Eğer hafif, katkısız referanslar tür bir yaklaşım peşindeyseniz, belki de yazdığım bu kod biraz işe yarayacaktır (% 100 sağlamlığı garanti edemiyorum).

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

[Bunun OP Sınırlamasını # 1 ihlal ettiğini fark ediyorum, ancak teknik olarak yazmadınız, yaptım]


3
Silverlight için ve bağımlılık olmadan çalışan tek cevap bu! Silverlight'ın JavascriptSerializer veya Serializable özelliği yoktur. Ve hiçbir bağımlılık Json.NET, RestSharp veya MiniJSON anlamına gelmez. Sadece @DanCsharpster başka bir olası çözümü denedi ama maalesef bu benim için işe yaramadı.
Cœur

1
JSON.NET gibi basit bir şeye referans eklemekle ilgili sorun nedir? Hiçbir şeye başvuramayacağınız kadar hafif olması gerekiyor mu? Kodunuzun işe yaramayacağını söylemiyorum, ancak kendi kodunuzu her döndürdüğünüzde, kodunuzun sağlam olmama riski, uç durumlar gibi şeyler için veya JSON.NET gibi test edilmiş bir kütüphane gibi hızlı bir şekilde çalıştırıldığını açıklıyorum.
Dan Csharpster

1
İyi bir alternatifiniz olduğunda kendi başınıza yuvarlanmak kötü bir fikirdir. Bu kadar hafif olması gereken bir durum bilmiyorum . Ve okuması ve değiştirmesi kolay daha az optimal kodum olmasını tercih ederim.
Ürdün

3
Başlangıçta bu kod parçasını yazdım çünkü alternatifim yoktu. Silverlight veya Office ürünleri için projeye dış referans eklemenin son derece sorunlu veya imkansız olduğu çeşitli türlerde sağlayıcılar düşünün.
dexy

Birkaç yıl sonra biliyorum, ama bu hala çok geçerli bir soru. SQL CLR C # ile çalışıyorsanız, neden bu kadar hafif gitmek isteyeceğimizi merak edenlere, kullanabileceğiniz ve System.RunTime.Serializationbunlardan biri olmayan çok sayıda "güvenli" kitaplık var , maalesef JSON.NET ve dolayısıyla da kullanılamaz. Mükemmel çalışmanız için teşekkürler dexy, dizilerin dizilerini serileştirmek için biraz geliştirmeye cesaret ettim, cevabımdaki güncellenmiş koda bakın .
Alberto Rechy

15

Sadece iç içe bir sözlüğü ayrıştırmam gerekiyordu ,

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

nerede JsonConvert.DeserializeObjectyardımcı olmaz. Aşağıdaki yaklaşımı buldum:

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

SelectTokenEğer istenilen alana aşağı kazmak sağlar. "x.y.z"JSON nesnesine inmek için bir yol bile belirtebilirsiniz .


JObject.Parse (json) .ToObject <Sözlük <Kılavuz, Liste <int> >> () senaryomda benim için çalıştı teşekkürler
geedubb

11

System.Text.Json

Bu artık System.Text.Jsonyerleşik olanı kullanarak yapılabilir .net core 3.0. Bu JSON serisini artık mümkün olmayan üçüncü şahıs kütüphaneleri kullanılarak.

var json = @"{""key1"":""value1"",""key2"":""value2""}";
var values = JsonSerializer.Deserialize<Dictionary<string, string>>(json);

.Net Standard veya .Net Framework kullanılıyorsa nu-get paketinde System.Text.Json da mevcuttur .


1
Evet! System.Text.Jsonbu günlere giden yol.
mfluehr

2
Evet, umut verici görünüyor! Ancak, .NET Core 3.1'in System.Text.Json'ın varsayılan sürümünün Sözlüklerin dizgesiz anahtarlarla serileştirilmesini desteklemediğini unutmayın. Benim OP dizeleri hakkında iken, şimdi pratikte, bir sürü Guid anahtar var, bu yüzden bu geçiş yapmaya çalışırken beni "bit". Ayrıca, bazı özelliklerin (gerekli vb.) Eşdeğerleri de yoktur.
richardtallent

6

Mark Rendle bunu bir yorum olarak yayınladı , bir cevap olarak göndermek istedim çünkü Google reCaptcha yanıtından başarıyı ve json hata kodlarını döndürmek için şimdiye kadar çalışan tek çözüm bu.

string jsonReponseString= wClient.DownloadString(requestUrl);    
IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;

Tekrar teşekkürler Mark!


1
JavaScriptSerializer neredeyse kullanımdan kaldırıldı. Belgeler JSON.NET kullanmamız gerektiğini söylüyor ( docs.microsoft.com/en-us/dotnet/api/… )
Mario Lopez

Ek bağımlılıklar eklemek istemediğiniz eski web formları uygulamaları için de iyidir.
Andrew Grothe

5

Düzenleme: Bu çalışır, ancak Json.NET kullanarak kabul edilen cevap çok daha basittir. Birisinin sadece BCL koduna ihtiyaç duyması durumunda bunu terk etmek

Kutusundan çıkan .NET çerçevesi tarafından desteklenmez. Göze batan bir gözetim - herkesin adlandırılmış özelliklere sahip nesnelere serileştirilmesi gerekmez. Sonunda kendimi yuvarladım:

<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

Aranan:

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 # ve VB.NET karışımı için üzgünüm…


2
[TestMethod] genel void TestSimpleObject () {const string json = @ "{" "Ad" ":" "Bob" "," "Yaş" ": 42}"; var dict = new JavaScriptSerializer (). IDerial <string, object> olarak DeserializeObject (json); Assert.IsNotNull (dict); Assert.IsTrue (dict.ContainsKey ( "Ad")); Assert.AreEqual ("Bob", dikte ["Ad"]); Assert.IsTrue (dict.ContainsKey ( "Yaş")); Assert.AreEqual (42, dikte ["Yaş"]); }
Mark Rendle

1
Bu fantastik. Tarayıcı tabanlı istemcilerle JSON kullanarak arabirim oluşturan WCF hizmeti uygulamalarına yardımcı olur.
Anton

@ Mark Rendle: Uygulamanız çok basit ve json sonuçlarını hem başarı hem de hata kodları almak için şimdiye kadar benim için çalışan SADECE. Birçok çözüm denedim, bu yüzden bunu yorum olarak gönderdiğiniz için teşekkür ederiz. Cevap bu olmalı.
Bryan

5

Burada jSnake04 ve Dasun tarafından gönderilen kodun üzerine ekledim. JArrayÖrneklerden nesne listeleri oluşturmak için kod ekledim . İki yönlü özyineleme vardır, ancak sabit, sonlu bir ağaç modelinde çalıştığı için, veriler çok büyük olmadığı sürece yığın taşması riski yoktur.

/// <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;
}

4

Diğer yanıta JSON null değerleri için bir denetim ekledim

Aynı problemim vardı, bu yüzden bunu kendim yazdım. Bu çözüm diğer cevaplardan farklıdır çünkü çoklu seviyelerde seriyi kaldırabilir.

Sadece deserializeToDictionary işlevine json dize göndermek güçlü yazılan olmayan Dictionary<string, object>nesne döndürecektir .

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

Örn: Bu Dictionary<string, object>, bir Facebook JSON yanıtının nesnesini döndürür .

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

Not: memleketi bir Dictionary<string, object>nesneye daha fazla serileştirme yapar .


1
+1 Yukarıda Dasun ile söylediğim gibi. Sadece olup olmadığını kontrol edebilirsiniz d.Value is JObject. Türleri kontrol etmek için yansıma yapmak zorunda değilsiniz. Ve isoperatörle null olup olmadığını kontrol etmeniz gerekmez. Nesne null olursa false değerini döndürür.
Ürdün

3

Buradaki tüm bu cevaplar, sadece bu küçük dizeyi daha büyük bir nesneden çıkarabileceğinizi varsayar ... ... büyük bir nesneyi, eşlemenin içinde bir yerde böyle bir sözlükle basitçe deserealize etmek isteyen insanlar ve System.Runtime.Serialization.Json DataContract sistemini bir çözüm:

Gis.stackexchange.com'da bir cevap bu ilginç bağlantıya sahipti . Bunu archive.org ile kurtarmak zorunda kaldım, ancak oldukça mükemmel bir çözüm sunuyor: özelIDataContractSurrogate tam olarak kendi türlerinizi uyguladığınız sınıf. Kolayca genişletebildim.

Yine de bir sürü değişiklik yaptım. Orijinal kaynak artık mevcut olmadığından, tüm sınıfı buraya göndereceğim:

using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;

namespace JsonTools
{
    /// <summary>
    /// Allows using Dictionary&lt;String,String&gt; and Dictionary&lt;String,Boolean&gt; types, and any others you'd like to add.
    /// Source: https://web.archive.org/web/20100317222656/my6solutions.com/post/2009/06/30/DataContractSerializer-DataContractJsonSerializer-JavaScriptSerializer-XmlSerializer-for-serialization.aspx
    /// </summary>
    public class JsonSurrogate : IDataContractSurrogate
    {
        /// <summary>
        /// Deserialize an object with added support for the types defined in this class.
        /// </summary>
        /// <typeparam name="T">Contract class</typeparam>
        /// <param name="json">JSON String</param>
        /// <param name="encoding">Text encoding</param>
        /// <returns>The deserialized object of type T</returns>
        public static T Deserialize<T>(String json, Encoding encoding)
        {
            if (encoding == null)
                encoding = new UTF8Encoding(false);
            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(
                typeof(T), new Type[0], int.MaxValue, true, new JsonSurrogate(), false);
            using (MemoryStream stream = new MemoryStream(encoding.GetBytes(json)))
            {
                T result = (T)deserializer.ReadObject(stream);
                return result;
            }
        }

        // make sure all values in this are classes implementing JsonSurrogateObject.
        private static Dictionary<Type, Type> KnownTypes = 
            new Dictionary<Type, Type>()
            {
                {typeof(Dictionary<String, String>), typeof(SSDictionary)},
                {typeof(Dictionary<String, Boolean>), typeof(SBDictionary)}
            };

        #region Implemented surrogate dictionary classes

        [Serializable]
        public class SSDictionary : SurrogateDictionary<String>
        {
            public SSDictionary() : base() {}
            protected SSDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
        }
        [Serializable]
        public class SBDictionary : SurrogateDictionary<Boolean>
        {
            public SBDictionary() : base() {}
            protected SBDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
        }

        #endregion

        /// <summary>Small interface to easily extract the final value from the object.</summary>
        public interface JsonSurrogateObject
        {
            Object DeserializedObject { get; }
        }

        /// <summary>
        /// Class for deserializing any simple dictionary types with a string as key.
        /// </summary>
        /// <typeparam name="T">Any simple type that will be deserialized correctly.</typeparam>
            [Serializable]
        public abstract class SurrogateDictionary<T> : ISerializable, JsonSurrogateObject
        {
            public Object DeserializedObject { get { return dict; } }
            private Dictionary<String, T> dict;

            public SurrogateDictionary()
            {
                dict = new Dictionary<String, T>();
            }

            // deserialize
            protected SurrogateDictionary(SerializationInfo info, StreamingContext context)
            {
                dict = new Dictionary<String, T>();
                foreach (SerializationEntry entry in info)
                {
                    // This cast will only work for base types, of course.
                    dict.Add(entry.Name, (T)entry.Value);
                }
            }
            // serialize
            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                foreach (String key in dict.Keys)
                {
                    info.AddValue(key, dict[key]);
                }
            }

        }

        /// <summary>
            /// Uses the KnownTypes dictionary to get the surrogate classes.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public Type GetDataContractType(Type type)
        {
            Type returnType;
            if (KnownTypes.TryGetValue(type, out returnType))
            {
                return returnType;
            }
            return type;
        }

        public object GetObjectToSerialize(object obj, Type targetType)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///     Gets the object out of the surrogate datacontract object. This function is the reason all surrogate objects need to implement the JsonSurrogateObject class.
        /// </summary>
        /// <param name="obj">Result of the deserialization</param>
        /// <param name="targetType">Expected target type of the deserialization</param>
        /// <returns></returns>
        public object GetDeserializedObject(object obj, Type targetType)
        {
            if (obj is JsonSurrogateObject)
            {
                return ((JsonSurrogateObject)obj).DeserializedObject;
            }
            return obj;
        }

        public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
        {
            return null;
        }

        #region not implemented

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

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

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

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

        #endregion
    }
}

Sınıfa yeni desteklenen türler eklemek için, sınıfınızı eklemeniz, ona doğru yapıcıları ve işlevleri vermeniz ( SurrogateDictionarybir örneğe bakın), miras aldığından emin olmanız JsonSurrogateObjectve tür eşlemesini KnownTypessözlüğe eklemeniz yeterlidir . Dahil olan SurrogateDictionary herhangi biri için temel oluşturabilirDictionary<String,T> T'nin doğru bir şekilde serileştirmeyi kaldıran herhangi tür olduğu tür .

Bunu aramak gerçekten basit:

MyObjtype newObj = JsonSurrogate.Deserialize<MyObjtype>(jsonStr, encoding);

Bazı nedenlerden dolayı bu şeyin boşluk içeren anahtar dizelerini kullanmada sorun yaşadığını unutmayın; sadece nihai listede yoktu. Sadece json özelliklerine karşı olabilir ve aradığım api zayıf bir şekilde uygulanmış olabilir, unutmayın; Bilmiyorum. Her neyse, bunu ham json verilerindeki alt çizgilerle değiştirerek ve serileştirmeden sonra sözlüğü düzelterek çözdüm.


Bu arada, tuhaf bir nedenden dolayı Mono bu şeyleri yürütmekte zorlanıyor gibi görünüyor ...
Nyerguds

Paylaştığınız için teşekkürler, ne yazık ki bu çözüm ilkel olmayan türleri desteklemiyor ve ham değeri elde etmenin bir yolu yok, böylece kendiniz oluşturabilirsiniz. Özel türümü KnownTypes'e kaydedip sözlükte kullanırsam, önce sözlüğü çağırır, en uzak türlerden daha karmaşık olanlara kadar aşağıdan yukarıya ayrıştırmaya başlamasını beklerdim.
Ivan Leonenko

Soru sadece sordu Dictionary<String,String>. Dürüst olmak gerekirse bu sistemle karmaşık türlerin serisini kaldırmayı denemedim.
Nyerguds

3

Yukarıdaki yorumlara dayanarak deneyinJsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json)

var json = @"{""key1"":1,""key2"":""value2"", ""object1"":{""property1"":""value1"",""property2"":[2,3,4,5,6,7]}}";
var parsedObject = JsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json);

karmaşık nesneler ve listeler için bile işe yarıyor gibi görünüyor.


1

Bunu RestSharp'ta yeni uyguladım . Bu gönderi bana yardımcı oldu.

Linkteki kodun yanı sıra, benim kodum. Şimdi Dictionaryböyle bir şey yaptığımda bir sonuç elde:

var jsonClient = new RestClient(url.Host);
jsonClient.AddHandler("application/json", new DynamicJsonDeserializer());
var jsonRequest = new RestRequest(url.Query, Method.GET);
Dictionary<string, dynamic> response = jsonClient.Execute<JObject>(jsonRequest).Data.ToObject<Dictionary<string, dynamic>>();

Beklediğiniz JSON türüne dikkat edin - benim durumumda, çeşitli özelliklere sahip tek bir nesne alıyordum. Ekteki bağlantıda yazar bir liste alıyordu.


1

Benim yaklaşımım arasında JObject veya ExpandObject olmadan IDictionary doğrudan serisini kaldırır. Kod, temel olarak JSON.NET kaynak kodunda bulunan ExpandoObjectConverter sınıfından kopyalanan ancak ExpandoObject yerine IDictionary kullanılarak dönüştürülen dönüştürücüyü kullanır.

Kullanımı:

var settings = new JsonSerializerSettings()
{
    Converters = { new DictionaryConverter() },
};
var result = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, settings);

Kod:

// based on ExpandoObjectConverter, but using arrays instead of IList, to behave similar to System.Web.Script.Serialization.JavaScriptSerializer
public class DictionaryConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return ReadValue(reader);
    }

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

    public override bool CanWrite
    {
        get { return false; }
    }

    private object ReadValue(JsonReader reader)
    {
        while (reader.TokenType == JsonToken.Comment)
        {
            if (!reader.Read())
                throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
        }

        switch (reader.TokenType)
        {
            case JsonToken.StartObject:
                return ReadObject(reader);
            case JsonToken.StartArray:
                return ReadList(reader);
            default:
                if (IsPrimitiveToken(reader.TokenType))
                    return reader.Value;

                throw JsonSerializationExceptionCreate(reader, string.Format(CultureInfo.InvariantCulture, "Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
        }
    }

    private object ReadList(JsonReader reader)
    {
        List<object> list = new List<object>();

        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.Comment:
                    break;
                default:
                    object v = ReadValue(reader);

                    list.Add(v);
                    break;
                case JsonToken.EndArray:
                    return list;
            }
        }

        throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
    }

    private object ReadObject(JsonReader reader)
    {
        IDictionary<string, object> dictionary = new Dictionary<string, object>();
        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.PropertyName:
                    string propertyName = reader.Value.ToString();

                    if (!reader.Read())
                        throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");

                    object v = ReadValue(reader);

                    dictionary[propertyName] = v;
                    break;
                case JsonToken.Comment:
                    break;
                case JsonToken.EndObject:
                    return dictionary;
            }
        }

        throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
    }

    //based on internal Newtonsoft.Json.JsonReader.IsPrimitiveToken
    internal static bool IsPrimitiveToken(JsonToken token)
    {
        switch (token)
        {
            case JsonToken.Integer:
            case JsonToken.Float:
            case JsonToken.String:
            case JsonToken.Boolean:
            case JsonToken.Undefined:
            case JsonToken.Null:
            case JsonToken.Date:
            case JsonToken.Bytes:
                return true;
            default:
                return false;
        }
    }

    // based on internal Newtonsoft.Json.JsonSerializationException.Create
    private static JsonSerializationException JsonSerializationExceptionCreate(JsonReader reader, string message, Exception ex = null)
    {
        return JsonSerializationExceptionCreate(reader as IJsonLineInfo, reader.Path, message, ex);
    }

    // based on internal Newtonsoft.Json.JsonSerializationException.Create
    private static JsonSerializationException JsonSerializationExceptionCreate(IJsonLineInfo lineInfo, string path, string message, Exception ex)
    {
        message = JsonPositionFormatMessage(lineInfo, path, message);

        return new JsonSerializationException(message, ex);
    }

    // based on internal Newtonsoft.Json.JsonPosition.FormatMessage
    internal static string JsonPositionFormatMessage(IJsonLineInfo lineInfo, string path, string message)
    {
        if (!message.EndsWith(Environment.NewLine))
        {
            message = message.Trim();

            if (!message.EndsWith(".", StringComparison.Ordinal))
                message += ".";

            message += " ";
        }

        message += string.Format(CultureInfo.InvariantCulture, "Path '{0}'", path);

        if (lineInfo != null && lineInfo.HasLineInfo())
            message += string.Format(CultureInfo.InvariantCulture, ", line {0}, position {1}", lineInfo.LineNumber, lineInfo.LinePosition);

        message += ".";

        return message;
    }
}

1

Tiny-JSON kullanabilirsiniz

string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);

1

Oyuna biraz geç, ancak yukarıdaki çözümlerin olmayanları beni saf ve basit bir .NET yönünde gösterdi, json.net çözümü yok. İşte burada, çok basit oldu. Standart .NET Json serileştirme ile nasıl çalıştığının tam çalışan bir örneğinin altında, örnek hem kök nesnede hem de alt nesnelerde sözlüğe sahiptir.

Altın mermi bu kedidir, ayarları serileştiriciye ikinci parametre olarak ayrıştırın:

DataContractJsonSerializerSettings settings =
                       new DataContractJsonSerializerSettings();
                    settings.UseSimpleDictionaryFormat = true;

Aşağıdaki tam kod:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

    namespace Kipon.dk
    {
        public class JsonTest
        {
            public const string EXAMPLE = @"{
                ""id"": ""some id"",
                ""children"": {
                ""f1"": {
                    ""name"": ""name 1"",
                    ""subs"": {
                    ""1"": { ""name"": ""first sub"" },
                    ""2"": { ""name"": ""second sub"" }
                    }
                },
                ""f2"": {
                    ""name"": ""name 2"",
                    ""subs"": {
                    ""37"": { ""name"":  ""is 37 in key""}
                    }
                }
                }
            }
            ";

            [DataContract]
            public class Root
            {
                [DataMember(Name ="id")]
                public string Id { get; set; }

                [DataMember(Name = "children")]
                public Dictionary<string,Child> Children { get; set; }
            }

            [DataContract]
            public class Child
            {
                [DataMember(Name = "name")]
                public string Name { get; set; }

                [DataMember(Name = "subs")]
                public Dictionary<int, Sub> Subs { get; set; }
            }

            [DataContract]
            public class Sub
            {
                [DataMember(Name = "name")]
                public string Name { get; set; }
            }

            public static void Test()
            {
                var array = System.Text.Encoding.UTF8.GetBytes(EXAMPLE);
                using (var mem = new System.IO.MemoryStream(array))
                {
                    mem.Seek(0, System.IO.SeekOrigin.Begin);
                    DataContractJsonSerializerSettings settings =
                       new DataContractJsonSerializerSettings();
                    settings.UseSimpleDictionaryFormat = true;

                    var ser = new DataContractJsonSerializer(typeof(Root), settings);
                    var data = (Root)ser.ReadObject(mem);
                    Console.WriteLine(data.Id);
                    foreach (var childKey in data.Children.Keys)
                    {
                        var child = data.Children[childKey];
                        Console.WriteLine(" Child: " + childKey + " " + child.Name);
                        foreach (var subKey in child.Subs.Keys)
                        {
                            var sub = child.Subs[subKey];
                            Console.WriteLine("   Sub: " + subKey + " " + sub.Name);
                        }
                    }
                }
            }
        }
    }

0

Rahatsız edici bir şekilde, varsayılan model bağlayıcılarını kullanmak istiyorsanız, bir POST formu gibi sayısal dizin değerlerini kullanmanız gerekecek gibi görünüyor.

Bu makaledeki aşağıdaki alıntıya bakın http://msdn.microsoft.com/en-us/magazine/hh781022.aspx :

Her ne kadar biraz mantıksız olsa da, JSON istekleri aynı gereksinimlere sahiptir - onlar da form sonrası adlandırma sözdizimine uymalıdır. Örneğin, önceki UnitPrice koleksiyonu için JSON yükünü ele alalım. Bu veriler için salt JSON dizisi sözdizimi şu şekilde temsil edilir:

[ 
  { "Code": "USD", "Amount": 100.00 },
  { "Code": "EUR", "Amount": 73.64 }
]

Ancak, varsayılan değer sağlayıcıları ve model bağlayıcıları, verilerin bir JSON form postası olarak gösterilmesini gerektirir:

{
  "UnitPrice[0].Code": "USD",
  "UnitPrice[0].Amount": 100.00,

  "UnitPrice[1].Code": "EUR",
  "UnitPrice[1].Amount": 73.64
}

Karmaşık nesne toplama senaryosu belki de geliştiricilerin karşılaştığı en yaygın sorunlu senaryolardan biridir çünkü sözdizimi mutlaka tüm geliştiriciler için belirgin değildir. Bununla birlikte, karmaşık koleksiyonlar göndermek için nispeten basit sözdizimini öğrendikten sonra, bu senaryolarla başa çıkmak çok daha kolay hale gelir.


0

Bunu kullanarak System.Runtime.Serialization.Json.NET 4.5'in bir parçası öneririz .

[DataContract]
public class Foo
{
   [DataMember(Name = "data")]
   public Dictionary<string,string> Data { get; set; }
}

Sonra şu şekilde kullanın:

var serializer = new DataContractJsonSerializer(typeof(List<Foo>));
var jsonParams = @"{""data"": [{""Key"":""foo"",""Value"":""bar""}] }";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonParams));

var obj = serializer.ReadObject(stream);
Console.WriteLine(obj);

Serileştirici nerede tanımlanır?
bnieland

..ve Category3MeasureModel nedir? Google'da isabet yok.
bnieland

1
Bu sadece projem için serileştirdiğim model sınıfı. O Foo sınıfı olması gerekiyordu, ama bütün bölümü üretim kodundan kopyaladım. Kendi Foo sınıfım gibi kendi tarzınızı yaratmalısınız. Daha basit hale getirmek için adını Foo olarak değiştirdim. Bu sadece json ve geri serileştirmek istediğiniz özelliklerin veya alanların bir sınıfı.
Dan Csharpster

1
@DanCsharpster Windows Phone 8.1 Silverlight üzerinde kodunuzun tam bir kopya geçmişiyle alıyorum: System.ServiceModel.Web.ni.dll dosyasında `` System.Security.SecurityException '' özel durumu oluştu, ancak kullanıcı tarafından işlenmedi kod Ek bilgiler: 'Veri' üyesi herkese açık olmadığından 'MyApp.Foo' veri sözleşmesi türünün serileştirilmesi kaldırılamaz. Üyeyi herkese açık hale getirmek bu hatayı düzeltir. Alternatif olarak, dahili üyelerin seri hale getirilmesini sağlamak için bunu dahili hale getirebilir ve montajınızda InternalsVisibleToAttribute niteliğini kullanabilirsiniz
Cœur

1
@DanCsharpster Ve üye (get; set; olmadan) özellik veri değiştirirken, ben: System.ServiceModel.Web.ni.dll 'System.ArgumentException' türünde bir ilk şans istisnası oluştu Ek bilgi: Nesnesi 'System.Object' türü 'System.Collections.Generic.Dictionary`2 [System.String, System.String]' türüne dönüştürülemiyor.
Cœur

0

JSON'u sözlüğe çevirmeye çalışan herkes için sadece bazı değerleri almak için. orada basit bir şekilde kullanarakNewtongsoft.JSON

using Newtonsoft.Json.Linq
...

JObject o = JObject.Parse(@"{
  'CPU': 'Intel',
  'Drives': [
    'DVD read/writer',
    '500 gigabyte hard drive'
  ]
}");

string cpu = (string)o["CPU"];
// Intel

string firstDrive = (string)o["Drives"][0];
// DVD read/writer

IList<string> allDrives = o["Drives"].Select(t => (string)t).ToList();
// DVD read/writer
// 500 gigabyte hard drive
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.