ASP.NET에서 JSON을 간단한 Dictionary <string, string>으로 직렬화 해제하려면 어떻게해야합니까?


682

POST를 통해 ASP.NET으로 다시 전송되는 JSON의 간단한 키 / 값 목록이 있습니다. 예:

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

강력한 형식의 .NET 개체로 역 직렬화하려고하지 않습니다.

나는 보통 오래된 Dictionary (Of String, String) 또는 그와 동등한 (해시 테이블, Dictionary (Of String, Object), 구식 StringDictionary가 필요합니다 .2 차원 문자열 배열이 저에게 효과적입니다.

ASP.NET 3.5에서 사용 가능한 모든 항목과 널리 사용되는 Json.NET (이미 클라이언트 의 직렬화 에 사용 하고 있음)을 사용할 수 있습니다.

분명히 이러한 JSON 라이브러리 중 어느 것도 이마를 뛰어 넘는 명백한 기능을 가지고 있지 않습니다. 강력한 계약을 통한 리플렉션 기반 역 직렬화에 전적으로 집중되어 있습니다.

어떤 아이디어?

한계 :

  1. 내 JSON 파서를 구현하고 싶지 않습니다.
  2. 아직 ASP.NET 4.0을 사용할 수 없습니다
  3. 더 이상 사용되지 않는 오래된 ASP.NET 클래스에서 JSON을 사용하지 않는 것이 좋습니다.

1
re : 제한 3, JavaScriptSerizlizerASP.NET MVC에서 사용되며 더 이상 사용되지 않습니다.
bdukes

17
json 문자열을 많은 다른 스택 오버 플로우를 넘지 않고 쉽게 사용할 수있는 것으로 변환하는 간단한 방법을 찾는 것이 얼마나 어려웠습니까? 다른 언어로는 쉽지만 Java와 C #은 삶을 어렵게 만드는 것처럼 보입니다.
user299709

답변:


893

Json.NET 이 이것을 수행합니다 ...

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

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

더 많은 예제 : Json.NET으로 컬렉션 직렬화


9
값이 정수인 경우에도 작동합니다. 그들은 자동으로 '문자열'로 캐스팅됩니까?
Highmastdon 2016 년

58
@Highmastdon 아니요. 사전에 역 직렬화하는 가장 좋은 방법 dynamic은 값의 유형 으로 사용 하는 것입니다.JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json);
Erik Schierboom

1
이 페이지에서 매우 지저분한 키 / 값 쌍으로 여러 가지 답변을 시도했으며 JSON.NET이 내가 시도한 유일한 방법이었습니다.
bnieland

15
json에서 키 값 쌍 배열을 사용하는 경우 작동하지 않습니다 [{key: "a", value: "1"}, {key: "b", value:"2"}].var dict = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(json);
Adrian

8
json.net이 값을 JObject로 생성하기 때문에 값이 중첩 된 객체 인 경우에도 작동하지 않습니다
Kugel

100

.NET에는 3.5 어셈블리 의 Dictionary<String, Object>비아 System.Web.Script.Serialization.JavaScriptSerializer유형 으로 JSON 문자열을 캐스트하는 방법이 내장되어 있음을 발견했습니다 System.Web.Extensions. 방법을 사용하십시오 DeserializeObject(String).

정적 .net 페이지 메소드에 컨텐츠 유형 'application / json'의 아약스 게시 (jquery를 통해)를 수행 할 때이 문제가 발생하여 유형 (단일 매개 변수가있는) 메소드 Object가이 사전을 마술처럼 받았다는 것을 알았습니다 .


5
그러나 내장 된 javascriptserializer는 json.net보다 버그가 많으므로 솔루션이 더 좋습니다. 예를 들어 javascriptseralizer는 빈 문자열 대신 null을 반환하며 nullable 속성 등에서는 전혀 작동하지 않습니다.
pilavdzice

1
@pilavdzice MS의 비표준 날짜 형식을 가정하므로 날짜를 구문 분석하려고 할 때의 재미는 말할 것도 없습니다.
기본

16
빠른 코드 예제 : var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();다음Dictionary<string, object> dict = (Dictionary<string, object>)jsSerializer.DeserializeObject(jsonString);
네이트 쿡

6
간단한 경우 Nate Cook의 예의 이점은 외부 DLL이 필요하지 않다는 것입니다. .Net 프레임 워크 만 사용할 수있는 독립 실행 형 콘솔에서 API에 액세스하고 있습니다.
Nick.T

@pilavdzice 더 자세히 설명해 주시겠습니까? "빈 문자열 대신 null 반환"항목을 재현 할 수 없습니다.SomeData: ""
jrh

51

인터넷을 검색하고이 게시물에 걸려 넘어지는 사람들을 위해 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"]);

흠, 나는 당신의 해결책을 시도했습니다 ... 나는이 { "id": "13", "value": true} 같은 json을 가지고 있으며 나를 위해 Dictionary <dynamic> 솔루션 작동
Marko

알았어 문제가있는 곳을 찾았다 ... 직렬 deserialize하기 위해 사전 선언 후 []를 추가해야합니다 ... 나의 블로그 게시물에 의견을 추가하고 있습니다 ... cheers;)
Marko

특정 데이터 세트를 반영하도록 답변을 업데이트했습니다. 동적으로 잘 작동합니다.
JP Richardson

방금 좀 더 유연하고 Silverlight를 지원하는 또 다른 JSON 파서를 작성했습니다. procbits.com/2011/08/11/…
JP Richardson

41

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

6
System.Web.Script 사용 참조 System.Web.Extensions 추가
패트릭 컬른

1
이 대답은 간단하고 .NET을 사용하기 때문에 가장 좋습니다 System.Web.Script.Serialization. 그냥 작동합니다. 심지어 "유효하지 않은"JSON을 사용할 수있었습니다 string json = "{'id':13, 'value': true}";.
styfle

호기심에서 OrdinalIgnoreCase 사전으로 직렬화 해제하는 동일한 방법이 있습니까?
batbaatar

38

나는 같은 문제가 있었으므로 이것을 내 자신을 썼다. 이 솔루션은 여러 수준으로 역 직렬화 할 수 있으므로 다른 답변과 차별화됩니다.

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>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> 개체 로 더 deserilize .

최신 정보

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

@Jordan 지적 해 주셔서 감사합니다.이 코드를 약간 수정했지만 지금은 가지고 있지 않습니다. 이 코드는 JArray 객체를 처리하지 않으므로 일단 코드를 업데이트합니다.
Dasun

1
문제가 아니다. isand as연산자 에 대한 학습이 크게 도움이되었고 내 코드를 단순화 했기 때문에 나는 그것을 언급합니다 .
Jordan

ToString을 호출 한 다음 다시 역 직렬화하기 때문에 작동하지만 효율적이지 않습니다. 아래의 Falko의 답변을보십시오. 소스 문자열을 한 번만 역 직렬화합니다.
Sergei Zinovyev

1
Falko의 답변은 데이터 구조를 미리 알고있는 경우에만 작동합니다. 이 솔루션은 모든 JSON 문자열에 사용할 수 있습니다.
Dasun

16

가볍고 추가되지 않은 참조 유형의 접근 방식을 사용하는 경우 방금 작성한이 코드가 작동합니다 (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))));
}

[이것이 OP 제한 # 1을 위반한다는 것을 알고 있지만 기술적으로는 작성하지 않았습니다.]


3
이것이 Silverlight에서 작동하고 의존하지 않는 유일한 대답입니다! Silverlight에는 JavascriptSerializer 또는 Serializable이 없습니다. 그리고 의존성이 없다는 것은 Json.NET, RestSharp 또는 MiniJSON이 없음을 의미합니다. @DanCsharpster 만 다른 가능한 솔루션을 시도했지만 불행히도이 방법처럼 작동하지 않았습니다.
Cœur

1
JSON.NET과 같은 간단한 것에 대한 참조를 추가하는 데 어떤 문제가 있습니까? 아무것도 참조 할 수없는 경량이어야합니까? 나는 당신의 코드가 작동하지 않는다고 말하지는 않지만, 당신이 자신의 코드를 굴릴 때, 분명히 코드가 강력하지 않을 수도 있습니다.
Dan Csharpster

1
좋은 대안이 있다면 나름대로 굴리는 것은 좋은 생각이 아닙니다. 나는 그렇게 가벼운 상황이 없다는 것을 알고 있습니다 . 그리고 읽기 쉽고 변경하기 쉬운 최적의 코드가 아닙니다.
Jordan

3
대안이 없었기 때문에 원래 코드를 작성했습니다. 프로젝트에 외부 참조를 추가하는 것이 매우 문제가 있거나 불가능한 Silverlight 또는 다양한 Office 제품 유형의 공급자를 고려하십시오.
dexy

나는 몇 년 후에 그것을 알고 있지만 이것은 여전히 ​​유효한 질문입니다. SQL CLR C #을 사용하여 작업하는 경우 왜 그렇게 가벼워 야하는지 궁금해하는 사람이라면 누구나 사용할 수 있고 System.RunTime.Serialization그 중 하나가 아닌 "안전한"라이브러리 만 있습니다. 불행히도 JSON.NET은 그것도 사용할 수 없습니다. 귀하의 탁월한 작업에 감사드립니다. 배열을 역 직렬화 할 수 있도록 약간 개선했습니다 . 내 답변의 업데이트 된 코드를 참조하십시오 .
Alberto Rechy

15

방금 중첩 된 사전 을 구문 분석해야했습니다.

{
    "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 객체로 더 나아가는 경로를 지정할 수도 있습니다 .


JObject.Parse (JSON) .ToObject <사전 <GUID, 내 시나리오 덕분에 나를 위해 일한 목록 <INT >>> ()
geedubb

11

System.Text.Json

이제는 System.Text.Json에 내장 된를 사용하여 수행 할 수 있습니다 .net core 3.0. 이제 타사 라이브러리 사용 하지 않고도 JSON을 직렬화 해제 할 수 있습니다 .

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

.Net Standard 또는 .Net Framework를 사용하는 경우 nu-get 패키지 System.Text.Json 에서도 사용할 수 있습니다 .


1
예! System.Text.Json요즘가는 길입니다.
mfluehr

2
예, 유망 해 보입니다! 그러나 .NET Core 3.1의 기본 버전 인 System.Text.Json은 문자열이 아닌 키를 사용하여 역 직렬화 사전을 지원하지 않습니다. 내 OP는 문자열에 관한 것이었지만 지금은 실제로 Guid 키가 많으므로 스위치를 만들 때이 비트가 "비트"입니다. 또한 일부 속성 (필수 등)과 동등한 항목이 없습니다.
richardtallent

6

Mark Rendle은 이것을 코멘트 로 게시했습니다 .Google reCaptcha 응답의 성공과 오류 코드 json 결과를 반환하기 위해 지금까지 노력한 유일한 솔루션이므로 답변으로 게시하고 싶습니다.

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

다시 한번 감사합니다, 마크!


1
JavaScriptSerializer는 거의 사용되지 않습니다. 이 문서는 JSON.NET을 사용해야한다고 말합니다 ( docs.microsoft.com/en-us/dotnet/api/… )
Mario Lopez

추가 종속성을 포함하지 않으려는 레거시 webforms 앱에도 좋습니다.
앤드류 Grothe

5

편집하다: 이것은 작동하지만 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을 혼합해서 죄송합니다…


2
[TestMethod] public void TestSimpleObject () {const 문자열 json = @ "{" "Name" ":" "Bob" "," "Age" ": 42}"; var dict = 새로운 JavaScriptSerializer (). DeserializeObject (json)를 IDictionary <string, object>; Assert.IsNotNull (dict); Assert.IsTrue (dict.ContainsKey ( "Name")); Assert.AreEqual ( "Bob", dict [ "이름"]); Assert.IsTrue (dict.ContainsKey ( "Age")); Assert.AreEqual (42, dict [ "Age"]); }
Mark Rendle

1
이건 끝내줘. 브라우저 기반 클라이언트에서 JSON을 사용하여 인터페이스하는 WCF 서비스 구현에 도움이됩니다.
Anton

@ Mark Rendle : 구현이 너무 간단하고 성공 및 오류 코드 json 결과를 얻는 데 지금까지 나에게 도움이 된 유일한 방법입니다. 많은 솔루션을 시도했지만 의견으로 게시 해 주셔서 감사합니다. 답이되어야합니다.
Bryan

5

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

4

JSON의 null 값 검사를 다른 답변에 추가했습니다.

나는 같은 문제가있어서 내 자신을 썼다. 이 솔루션은 여러 수준으로 역 직렬화 할 수 있으므로 다른 답변과 차별화됩니다.

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>개체를 직렬화 해제 합니다.


1
+1 위의 Dasun과 말했듯이. 당신은 그냥 여부를 확인할 수 d.Value is JObject있습니다. 유형을 확인하기 위해 리플렉션을 거치지 않아도됩니다. 그리고 is연산자를 사용하면 null을 확인할 필요가 없습니다. 객체가 null 인 경우는 false를 돌려줍니다.
Jordan

3

여기에있는 모든 답변은 더 큰 객체에서 작은 문자열을 얻을 수 있다고 가정합니다 ... 매핑 내부의 어딘가에 그러한 사전을 사용하여 큰 객체를 단순히 비 시리얼 화하려는 사람들과 System.Runtime.Serialization.JsonDataContract 시스템을 사용하는 사람은 여기 있습니다. 해결책 :

gis.stackexchange.com에 대한 답변 에는 이 흥미로운 링크가 있습니다. 나는 archive.org로 그것을 복구해야했지만, IDataContractSurrogate당신이 정확히 자신의 유형을 구현 하는 사용자 정의 클래스 인 거의 완벽한 솔루션을 제공합니다 . 쉽게 확장 할 수있었습니다.

그래도 많은 변화를주었습니다. 원본 소스를 더 이상 사용할 수 없으므로 전체 클래스를 여기에 게시합니다.

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

지원되는 새로운 유형을 클래스에 추가하려면 클래스를 추가하고 올바른 생성자 및 함수를 SurrogateDictionary제공하고 (예를 참조하십시오) 상속하는지 확인 JsonSurrogateObject하고 유형 맵핑을 KnownTypes사전에 추가하십시오 . 포함 된 SurrogateDictionary는Dictionary<String,T> T가 올바르게 역 직렬화되는 유형 인 유형의 있습니다.

그것을 부르는 것은 정말 간단합니다.

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

어떤 이유로 공백이 포함 된 키 문자열을 사용하면 문제가 발생합니다. 그들은 단순히 최종 목록에 없었습니다. 단순히 json 사양에 위배되며 내가 호출 한 API가 제대로 구현되지 않았을 수 있습니다. 난 몰라 어쨌든 원시 json 데이터에서 밑줄로 정규 표현식을 바꾸고 역 직렬화 후 사전을 수정 하여이 문제를 해결했습니다.


그건 그렇고, 특이한 이유로 Mono는이 물건을 실행하는 데 문제가있는 것 같습니다 ...
Nyerguds

공유해 주셔서 감사합니다. 불행히도이 솔루션은 기본이 아닌 유형을 지원하지 않으며 원시 가치를 얻을 수있는 방법이 없으므로 직접 구성 할 수 있습니다. KnownTypes에 사용자 정의 유형을 등록하고 사전에서 사용하는 경우 사전을 먼저 호출하면 가장 원격 유형에서 더 복잡한 유형으로 맨 위에서 구문 분석을 시작할 것으로 예상됩니다.
Ivan Leonenko

글쎄, 질문은에 대해서만 물었다 Dictionary<String,String>. 나는 솔직히이 시스템으로 복잡한 유형을 역 직렬화하려고 시도하지 않았습니다.
Nyerguds

3

위의 의견을 바탕으로 시도하십시오JsonConvert.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);

복잡한 객체와 목록에서도 작동하는 것 같습니다.


1

방금 RestSharp 에서 이것을 구현했습니다 . 이 포스트 이 도움 .

링크의 코드 외에도 내 코드가 있습니다. 지금은 얻을 Dictionary나는 같은 것을 할 때 결과를 :

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

기대하는 JSON을 염두에 두십시오. 필자의 경우 여러 속성을 가진 단일 객체를 검색했습니다. 첨부 된 링크에서 저자가 목록을 검색하고있었습니다.


1

내 접근 방식은 JObject 또는 ExpandObject를 사용하지 않고 IDictionary로 직접 직렬화 해제합니다. 이 코드는 기본적으로 JSON.NET 소스 코드에있는 ExpandoObjectConverter 클래스에서 복사되지만 ExpandoObject 대신 IDictionary를 사용하여 변환기를 사용합니다.

용법:

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

암호:

// 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을 사용할 수 있습니다

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

1

게임에 약간 늦었지만 위의 솔루션 중 어느 것도 json.net 솔루션이 아닌 순수하고 간단한 .NET의 방향을 지적했습니다. 그래서 여기는 매우 간단합니다. 표준 .NET Json 직렬화로 수행되는 방법에 대한 전체 실행 예제 아래의 예제에는 루트 오브젝트와 하위 오브젝트 모두에 사전이 있습니다.

황금 총알이 고양이입니다. 설정을 serializer의 두 번째 매개 변수로 구문 분석하십시오.

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

아래의 전체 코드 :

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

짜증나게도 기본 모델 바인더를 사용하려면 POST 형식의 숫자 색인 값을 사용해야하는 것처럼 보입니다.

이 기사 http://msdn.microsoft.com/en-us/magazine/hh781022.aspx 에서 발췌 한 다음 내용을 참조 하십시오 .

다소 반 직관적이지만 JSON 요청의 요구 사항도 동일합니다. 또한 이름 지정 구문 양식을 준수해야합니다. 예를 들어 이전 UnitPrice 컬렉션에 대한 JSON 페이로드를 예로 들어 보겠습니다. 이 데이터의 순수한 JSON 배열 구문은 다음과 같이 표현됩니다.

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

그러나 기본 값 제공자 및 모델 바인더는 데이터를 JSON 양식 게시물로 표시해야합니다.

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

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

복잡한 객체 수집 시나리오는 아마도 모든 개발자에게 구문이 분명하지 않기 때문에 개발자가 직면하는 가장 광범위하게 문제가되는 시나리오 중 하나 일 수 있습니다. 그러나 복잡한 컬렉션을 게시하기위한 비교적 간단한 구문을 배우면 이러한 시나리오를 훨씬 쉽게 처리 할 수 ​​있습니다.


0

나는 그것을 사용 System.Runtime.Serialization.Json하는 것이 .NET 4.5의 일부라고 제안 합니다.

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

그런 다음 다음과 같이 사용하십시오.

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

시리얼 라이저는 어디에 정의되어 있습니까?
bnieland

.. 그리고 Category3MeasureModel은 무엇입니까? Google에서 조회수가 없습니다.
bnieland

1
그것은 내 프로젝트를 위해 직렬화하는 모델 클래스 일뿐입니다. Foo 클래스라고 가정하지만 프로덕션 코드에서 전체 섹션을 복사했습니다. 내 Foo 클래스와 같이 자신 만의 것을 만들어야합니다. 더 간단하게하기 위해 Foo로 이름을 바꿨습니다. json으로 직렬화하려는 속성 또는 필드의 클래스 일뿐입니다.
Dan Csharpster

1
@DanCsharpster Windows Phone 8.1 Silverlight에서 코드를 정확하게 복사하여 붙여 넣습니다.`System.ServiceModel.Web.ni.dll에서 'System.Security.SecurityException'유형의 예외가 발생했지만 사용자가 처리하지 못했습니다. 코드 추가 정보 : 멤버 'Data'가 공개되지 않으므로 데이터 계약 유형 'MyApp.Foo'를 역 직렬화 할 수 없습니다. 회원을 공개하면이 오류가 해결됩니다. 또는 내부 멤버를 직렬화하고 어셈블리에서 InternalsVisibleToAttribute 특성을 사용하여 내부 멤버를 직렬화 할 수 있습니다.
Cœur

1
@DanCsharpster 그리고 속성 데이터를 멤버로 변경하면 (get; set;없이) 다음과 같은 결과가 나타납니다 .System.ServiceModel.Web.ni.dll에서 'System.ArgumentException'유형의 첫 번째 예외가 발생했습니다. 'System.Object'유형은 'System.Collections.Generic.Dictionary`2 [System.String, System.String]'유형으로 변환 할 수 없습니다.
Cœur

0

일부 값을 검색하기 위해 JSON을 사전으로 변환하려는 사람에게 적합합니다. 이 간단한 방법 사용은Newtongsoft.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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.