Pergunta

Estou tentando usar o JSON.NET Framework em um formulário do Windows para ler algumas informações de uma string json. Mas estou lutando para obter os dicionários da matriz 'Taxonomies-> Topics' e dos 'Clusters'

{
    "keywords": {
        "anyString": [

        ],
        "allString": {
            "a5349f533e3aa3ccbc27de2638da38d6": "olympics"
        },
        "exactString": [

        ],
        "notString": [

        ],
        "highlightString": [

        ]
    },
    "dates": {
        "startDate": "15-01-2008",
        "endDate": "15-09-2009",
        "useDates": true
    },
    "clusters": {
        "permission": {
            "1": "private\/n"
        }
    },
    "taxonomies": {
        "Topics": {
            "2488": "Olympics 2012 (not participation)",
            "8876": "Olympics and culture"
        },
        "Keywords": {
            "8848": "Engineering in the Olympics"
        }
    },
    "sort": {
        "sortId": 1,
        "sortType": 2,
        "sort": "datetime",
        "sortOrder": "descending"
    }
}

Com o código abaixo, pude ler algumas das informações.

JObject searchCriteria = JObject.Parse(contentSearchCriteria);  
//search criteria   
IEnumerable<string> allString = searchCriteria["keywords"]["allString"].Children().Values<string>();
IEnumerable<string> anyString = searchCriteria["keywords"]["anyString"].Children().Values<string>();
IEnumerable<string> notString = searchCriteria["keywords"]["notString"].Children().Values<string>();
IEnumerable<string> exactString = searchCriteria["keywords"]["exactString"].Children().Values<string>();
IEnumerable<string> highlightString = searchCriteria["keywords"]["highlightString"].Children().Values<string>();
//dates
string startDate = (string)searchCriteria["dates"]["startDate"];
string endDate = (string)searchCriteria["dates"]["endDate"];
bool useDates = (bool)searchCriteria["dates"]["useDates"];

//sort
int sortId = (int)searchCriteria["sort"]["sortId"];
int sortType = (int)searchCriteria["sort"]["sortType"];
string sort = (string)searchCriteria["sort"]["sort"];
string sortOrder = (string)searchCriteria["sort"]["sortOrder"];

ATUALIZAR:

Como recomendado, adicionei

class SMSearchCriteria
    {
        public SMKeywords keywords { get; set; }
        public SMDates dates { get; set; }
        public SMClusters clusters { get; set; }
        public SMTaxonomies taxonomies { get; set; }
        public SMSort sort { get; set; }
    }

    class SMKeywords
    {
        public List<Dictionary<string, string>> AnyString {get; set;}
        public List<Dictionary<string, string>> AllString { get; set; }
        public List<Dictionary<string, string>> ExactString { get; set; }
        public List<Dictionary<string, string>> NotString { get; set; }
        public List<Dictionary<string, string>> HighlightString { get; set; } 
    }

    class SMDates
    {
        public string startDate { get; set; }
        public string endDate { get; set; }
        public bool useDates { get; set; }
    }

    class SMClusters
    {
        List<SMCluster> cluster;
    }

    class SMCluster
    {
        public Dictionary<string, string> cluster { get; set; }
    }

     class SMTaxonomies
    {
         public List<SMTaxonomy> taxonomies { get; set; }
    }

     class SMTaxonomy
     {
         public Dictionary<string, List<SMCategory>> taxonomy { get; set; }
     }

     class SMCategory
     {
         public Dictionary<int, string> category { get; set; }
     }

     class SMSort
    {
        public int sortId { get; set; }
        public int sortType { get; set; }
        public string sort { get; set; }
        public string sortOrder { get; set; }
    }

Mas quando eu executo:

    var mydata = JsonConvert.DeserializeObject<SMSearchCriteria>(contentSearchCriteria);

Eu recebo a exceção:

[Newtonsoft.Json.JsonSerializationException] = {"Cannot deserialize JSON object into type 'System.Collections.Generic.List`1[System.Collections.Generic.Dictionary`2[System.String,System.String]]'."}

Atualização 2:

Conforme sugerido, removi todas as listas extras e simplifiquei as classes para isso:

class SearchMasterSearchCriteria
    {
        public SMKeywords keywords { get; set; }
        public SMDates dates { get; set; }
        public Dictionary<string, Dictionary<int, string>> clusters { get; set; } 
        public Dictionary<string, Dictionary<int, string>> taxonomies { get; set; } 
        public SMSort sort { get; set; }
    }

    class SMKeywords
    {
        public Dictionary<string, string> anyString {get; set;}
        public Dictionary<string, string> allString { get; set; }
        public Dictionary<string, string> exactString { get; set; }
        public Dictionary<string, string> notString { get; set; }
        public Dictionary<string, string> highlightString { get; set; } 
    }

    class SMDates
    {
        public string startDate { get; set; }
        public string endDate { get; set; }
        public bool useDates { get; set; }
    }

     class SMSort
    {
        public int sortId { get; set; }
        public int sortType { get; set; }
        public string sort { get; set; }
        public string sortOrder { get; set; }
    }

Eu também adicionei código de teste para serializar o objeto como este:

//criteria
            SearchMasterSearchCriteria smCriteria = new SearchMasterSearchCriteria();

            //keywords
            SMKeywords smKeywords = new SMKeywords(); ;
            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("a5349f533e3aa3ccbc27de2638da38d6", "olympics");
            dict.Add("9cfa7aefcc61936b70aaec6729329eda", "games");
            smKeywords.allString = dict;

            //category
            Dictionary<int, string> categorieDict = new Dictionary<int, string>();
            categorieDict.Add(2488, "Olympics 2012 (not participation)");
            categorieDict.Add(8876, "Olympics and culture");

            //taxonomies
            Dictionary<string, Dictionary<int, string>> taxonomiesDict = new Dictionary<string, Dictionary<int, string>>();
            taxonomiesDict.Add("Topics", categorieDict);

            //metadata
            Dictionary<int, string> metadataDict = new Dictionary<int, string>();
            metadataDict.Add(1, @"private/n");

            //clusters
            Dictionary<string, Dictionary<int, string>> clustersDict = new Dictionary<string, Dictionary<int, string>>();
            clustersDict.Add("permission", metadataDict);


            //dates
            SMDates smDates = new SMDates();
            smDates.startDate = "15-01-2008";
            smDates.endDate = "15-09-2009";
            smDates.useDates = true;

            //sort
            SMSort smSort = new SMSort();
            smSort.sortId = 1;
            smSort.sortType = 2;
            smSort.sort = "datetime";
            smSort.sortOrder = "descending";

           //add to criteria.
            smCriteria.keywords = smKeywords;
            smCriteria.clusters = clustersDict;
            smCriteria.taxonomies = taxonomiesDict;
            smCriteria.dates = smDates;
            smCriteria.sort = smSort;

            //serialize
            string json = JsonConvert.SerializeObject(smCriteria);
            var mydata1 = JsonConvert.DeserializeObject<SearchMasterSearchCriteria>(json);

Naquela época, a única diferença entre as 2 cordas json onde. o [] e os nulos para qualquer coisa, exato, etc., então eu substituí os colchetes vazios para os encaracolados e ela se desfaz sem erros :)

contentSearchCriteria = contentSearchCriteria.Replace("[]", "{}");
var mydata = JsonConvert.DeserializeObject<SearchMasterSearchCriteria>(contentSearchCriteria);
Foi útil?

Solução

Para ser sincero com você, eu não faria da maneira que você está fazendo isso. Aqui está a maneira como eu vou recuperar os dados:

class Data {
     Dictionary<string, Dictionary<string, string>> keywords;
     DatesClass dates;
     .......

}

class DatesClass
{
    string startDate;
    string endDate;
    bool? useDates

}


var mydata = JsonConvert.DeserializeObject<Data>(jsonstring);

Eu não preenchi a classe de dados inteira, mas você entendeu. Achei muito mais fácil criar um objeto na estrutura dos seus dados de entrada e, em seguida, usar o método DeserializeObject para preencher os dados. Isso também torna o código muito mais limpo e permite que o compilador verifique erros de digitação.

Outras dicas

Sim, seu problema agora está na maneira como JSON.NET desaperializa os objetos. No json.net, uma classe C# se torna um objeto JSON. E um membro dessa classe se torna uma chave com o valor do membro se tornando o valor.

Vamos dar o exemplo do caminho da taxonomia como exemplo. Usando sua definição de classe acima, o JSON.NET está procurando dados JSON neste formato:

{"taxonomies": {"taxonomies":[{"taxonomy": {"Topics": {1212, "foo"}}}]}

Isso não se parece nada com seus dados de entrada.

Quando você está criando seus objetos, pense dessa maneira.

1) Um objeto base cria um {} no código JSON. 2) Um dicionário cria um {} no código JSON. 3) Uma lista cria um [] no código JSON 4) Todo membro de uma classe cria uma entrada no {} do código JSON

O que pode ajudar a depurar isso para você é criar sua estrutura, preencher alguns dados temp e usar o jsonConvert.serialize (myobj) para mostrar como JSON acha que a estrutura será.

Eu acho que sua exceção vem de ter caminho para muitas aulas.

Provavelmente é assim que você deseja que a parte dos Taxominies do seu código seja:

class SMSearchCriteria
{
        public SMKeywords keywords { get; set; }
        public SMDates dates { get; set; }
        public SMClusters clusters { get; set; }
        public SMTaxominies taxonomies { get; set; }
        public SMSort sort { get; set; }
}

class SMTaxominies
{
    public Dictionary<string, string> Topics;
    public Keywords<string, string> Keywords;
}

Eu começaria com uma classe DTO fortemente ticked primeiro, de preferência, um DataContract dessa maneira que você tem a opção de seriar a qualquer formato que desejar, por exemplo, JSON, XML, Protobuf, etc.

NOTA: JSON é realmente muito lento para serializar/desarrializar em comparação com a maioria dos outros formatos (veja: Benchmarks de serialização - Json.net é 'newtonsoft.json') Se você estiver fazendo um aplicativo cliente rico em vez de aplicativo da web, você pode escolher um formato de serialização diferente. Independentemente de qual formato você acabar, você ainda pode reutilizar o mesmo DTO, por exemplo, seu código acima se parece:

[DataContract]
public class MyDto
{
  [DataMember]
  public Keywords keywords { get; set; }
}

[DataContract]
public class Keywords
{
  [DataMember]
  public List<string> anyString { get; set; }

  [DataMember]
  public Dictionary<string,string> allString { get; set; }

  [DataMember]
  public List<string> exactString { get; set; }

  [DataMember]
  public List<string> notString { get; set; }

  [DataMember]
  public List<string> highlightString { get; set; }
}

var dto = new MyDto { Keywords = { allString = {{"a5349f533e3aa3ccbc27de2638da38d6", "olympics"}} };

var json = JsonConvert.SerializeObject(dto);
var fromJson = JsonConvert.DeserializeObject<MyDto>(json);

Editar: links adicionados

Parece que você pode estar tendo problemas com o JSON.NET, caso em que você deve tentar outros serializadores/desrializadores do JSON .NET. A Microsoft envia um sistema.runtime.serialization.json.datacmotractjSonserializer incluída no .net v3.5. Aqui estão algumas aulas de auxiliar, mostrando como você serializar e desserializar JSON.

Jayrock é outro serializador JSON para .NET, mas é mais lento que o resto e acho que não tem um bom suporte para genéricos.

Por que você não usa o LINQ para JSON?

Por exemplo, colocar seus nós de "classificar" mapeados para sua classe

var jsonResult = JObject.Parse(jsonString);

var sortItem = from s in jsonResult["sort"]
select new MySortObject{
                            SortId = s.Value<int>("sortId")
                        };

http://www.newtonsoft.com/json/help/html/queryjsonlinq.htm

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top