JsonConvert unexpected behavior when serialising Dictionary - c#

Hell all! I have a Dictionary<string,Dictionary<CustomClass,string>> that i want to serialise.
The result I expect is something like:
{
"key1":{
{
"CustomClassProperty1":"val1",
"CustomClassProperty2":"val2",
"CustomClassProperty3":"val3"
}:"Final STR",
{
"CustomClassProperty1":"val10",
"CustomClassProperty2":"val2",
"CustomClassProperty3":"val35"
}:"Final STR4",
{
"CustomClassProperty1":"val100",
"CustomClassProperty2":"val25",
"CustomClassProperty3":"val300"
}:"Final STR8"
},
"key2":{
{
"CustomClassProperty1":"val4",
"CustomClassProperty2":"val5",
"CustomClassProperty3":"val6"
}:"Final STR 2"
},
"key3":{
{
"CustomClassProperty1":"val1",
"CustomClassProperty2":"val7",
"CustomClassProperty3":"val5"
}:"Final STR 3",
{
"CustomClassProperty1":"val10",
"CustomClassProperty2":"val2",
"CustomClassProperty3":"val35"
}:"Final STR0",
{
"CustomClassProperty1":"val100",
"CustomClassProperty2":"val25",
"CustomClassProperty3":"val300"
}:"Final STR10"
}
}
But instead i'm getting
{
"key1":{
"MyProjectNamespace.CustomClass":"Final STR",
"MyProjectNamespace.CustomClass":"Final STR4"
},
"key2":{
"MyProjectNamespace.CustomClass":"Final STR 2"
},
"key3":{
"MyProjectNamespace.CustomClass":"Final STR 3"
}
}
Can anyone tell me how to make it right? I dont want the "namespace.classname" but the properties... I`m using Newtonsoft.Json btw... tks a lot!

Your desired output isn't in JSON format. The left hand side of the : is the name of the object property, and must be a string. To get the format you've listed, you'll need to use another serializer that supports your non-JSON format.

Related

Newtonsoft Add a Keyed JObject in JArray

I have tried numerous times and also tried to consult the documentation provided by Newtonsoft website but there doesn't seem to be any answer regarding my issue. I have also searched Google for no avail, wasted around 4 hours with no answer but just to continue without it.
My issue is that can't add a JObject into a JArray with a Key. I understand it seems rather simple task but whatever I tried ended up in an Exception being thrown out.
I am trying to write a simple file with the following layout:
{
"items" : [
"item 1" : { },
"item 2" : { },
]
}
// the actual layout that I have is
{
"items" : [
{ },
{ },
]
}
I can successfully add the first items key for JArray through jobj["items"] = jarray but I cant seem to use the same technique with JArray. I need to add items in JArray through JArray.Add() and it doesn't let me provide a key. I'm actually lost on this. Can someone please explain as how can I achieve the above layout? Thank you.
As #dbc mentioned, the format which you require is not valid. The nearest valid format you could achieve is as following.
{
"items":
{
"item 1":{},
"item 2":{}
}
}
You could achieve it using a Data structure containing a Dictionary. For Example
var data = new DataStructure{
items = new Dictionary<string,Item>()
{
["Item 1"] = new Item{},
["Item 2"] = new Item{}
}};
Where DataStructure and Item is defined as
public class DataStructure
{
public Dictionary<string,Item> items{get;set;}
}
public class Item
{
}
If you do not want to create concrete class, you can achieve the same using anonymous types
var data = new {items = new Dictionary<string,Item>()
{
["Item 1"] = new Item{},
["Item 2"] = new Item{}
}};
or, if you want to avoid creation of Item Class as well
var data = new {items = new Dictionary<string,object>()
{
["Item 1"] = new {},
["Item 2"] = new {}
}};
Output
{
"items": {
"Item 1": {},
"Item 2": {}
}
}
As it has been suggested in the comment, my desired layout is not a right one. As it appears json needs an anonymous object within the array to hold a keyed object.
So the layout should be:
{
"items" : [
{
"item1" : { }
},
.......
]
}

Selecting value from a JSON string

I am having a heck of a time getting a particular value from json and am hoping someone can help. The json I'm using comes from a form post, so will typically be different each time, but the IDs will always be the same (just like every form!)...and I do not have control over the format of the json. I am able to get the name value from this just fine (using Newtonsoft.Json), but am stuck on how to get the "More then 5 years" value...
Here is what I am using to get the "My name is" value, which (obviously) doesn't work for "Years of Employment".
C#:
obj["form_response"]["answers"].SelectToken("$.[?(#field.id == '26')]..text").ToString();
JSON:
{
"event_type":"form_response",
"form_response":{
"definition":{
"id":"c33500e5",
"title":"Employee Satisfaction",
"fields":[
{
"id":"33",
"title":"Years of employment:",
"type":"multiple_choice"
},
{
"id":"26",
"title":"My name is:",
"type":"short_text"
}
]
},
"answers":[
{
"type":"choice",
"choice":{
"label":"More than 5 years"
},
"field":{
"id":"33",
"type":"multiple_choice"
}
},
{
"type":"text",
"text":"Bill Dunn",
"field":{
"id":"26",
"type":"short_text"
}
}
]
}
}
The value you want is nested as follows: { "choice": { "label": "More than 5 years", ... } } so you can do:
var result = obj["form_response"]["answers"].SelectToken("$.[?(#field.id == '33')].choice.label");
var resultJson = result.ToString();

JSON element reader .NET

I have a simple JSON example like this :
{
"items": {
"element": ["item 1","item 2"]
},
"name": "James"
}
and a JSON Schema like this :
{
'type': 'object',
'properties': {
'name': {'type':'string'},
'items': {
'type': 'object',
'properties':{
'element':{
'type':'array',
'items':[{'type':'string', 'type':'string'}]
}
}
}
},
'additionalProperties': false
}
Calling "IsValid()" method in JSON.NET using the given Schema and Data will return VALID.
Question :
How do I traverse and edit the elements inside JSON ?
My objective is to look-up values of node "element" in database and then replace it with a generalized value if they exists e.g "item 1" exists in database and will replaced with "general value A". However, "item 2" doesn't exist in database and should throw some kind of error message when IsValid() method is called.
Note that this is a desktop application using .NET 4.5 and JSON.NET library, and it will be used as a data-cleansing tool. I'm open to any kind of alternative libraries as long as they are compatible with .NET 4.5 though..
Not fully understand the part of your question with IsValid() issue, but if talk about traversing through json elements and editing, you can use 2 methods.
Install Newtonsoft.Json at first in Package-Manager in VS: Install-package newtonsoft.json.
Create class JsonItems, which describes your input JSON hierarchy
class JsonItems
{
public Items items;
public string name;
}
class Items
{
public List<string> elements { get; set; }
}
Now you can legally deserialize your json and edit result as any .net object.
string jsonItems = #"{
'items': {
'element': ['item 1','item 2']
},
'name': 'James'
}";
var result = JsonConvert.DeserializeObject<JsonItems>(jsonItems);
result.items = new Items
{
elements = new List<string> {"itemd 3", "item 4"}
};
2. The second way is more quick (in implementation), but less secuarble in runtime. With help of dynamic.
dynamic d = JObject.Parse(jsonItems);
d.items.element[1] = "item 3";

Json.NET SelectTokens not working if json contains empty array

I have a valid JSON object that contains multiple "en-US" keys, which I'm trying select. For that purpose I use the JsonPath
"$..en-US"
which is given to the SelectTokens procedure implemented by the Json.NET. It's a JSON framework for .NET . Everything is working fine and well as long as my JSON doesn't contain any empty array.
Here's an example:
var myJsonPath = "$..en-US";
var myJson =
#"{
'controls': [
{
'messages': {
'addSuggestion': {
'en-US': 'Add'
}
}
},
{
'header': {
'controls': []
},
'controls': [
{
'controls': [
{
'defaultCaption': {
'en-US': 'Sort by'
},
'sortOptions': [
{
'label': {
'en-US': 'Name'
}
}
]
}
]
}
]
}
]
}";
var jToken = JObject.Parse(myJson);
var tokens = jToken.SelectTokens(myJsonPath);
Here, the tokens variable will contain just one element! That will be the "en-US" occurence BEFORE the empty array in the 'controls' of the 'header' object. However, when I just leave this 'header' object out:
var myJson =
#"{
'controls': [
{
'messages': {
'addSuggestion': {
'en-US': 'Add'
}
}
},
{
'controls': [
{
'controls': [
{
'defaultCaption': {
'en-US': 'Sort by'
},
'sortOptions': [
{
'label': {
'en-US': 'Name'
}
}
]
}
]
}
]
}
]
}";
I will get all the 3 occurencies of the "en-US" as expected. Btw, if I validate my JsonPath on the first JSON object (i.e. which contains an empty array) in an online tool, then as expected, I get all the three "en-US" cases. This diverges from what I'm getting from the Json.NET. I'm wondering whether it's a bug or do I have to handle this case manually somehow?
This is a bug that has been fixed. Upgrade to the latest version of Json.NET.
If you're in the same situation as me where you're a bit stuck with respect to updating your version of Json.NET, you can work around the issue by doing something along the lines of this:
IEnumerable<JValue> vals = jToken
.Desecendants()
.Where(w => w is JProperty && w.Name=="en-US")
.Select(s => s.Value);
Hope that helps! The vals array will contain the same tokens you would have gotten using the selector you were trying to use before.

Generate lightweight JSON using DataContractJsonSerializer

I'm trying to generate JSON using C# and DataContractJsonSerializer in .Net 3.5. The problem is that I can't figure out how to build the structure correct for the result I need.
I've tried to reproduce PHP's associative arrays using both hashtables, list objects and arraylists but can't figure out how to generate my result in the best way using DataContractJsonSerializer without having to create my own recursive loop for building JSON.
The closest approach is using the a Dictionary < string, Dictionary < string, string>> aproach but the result is too big as I can't "name" the keys.
This is what I get:
[
{
"Key":"status",
"Value":[
{
"Key":"value",
"Value":"ok"
}
]
},
{
"Key":"1",
"Value":[
{
"Key":"name",
"Value":"Result1"
},
{
"Key":"details",
"Value":"Result 1 details"
}
]
},
{
"Key":"2",
"Value":[
{
"Key":"name",
"Value":"Result2"
},
{
"Key":"details",
"Value":"Result 2 details"
}
]
},
{
"Key":"caller",
"Value":[
{
"Key":"value",
"Value":"1135345"
}
]
}
]
This is what I want:
{
"status":"ok",
"response":[
{
"id":1,
"name":"Result1"
"details":"Result 1 details"
},
{
"id":2,
"name":"Result2"
"details":"Result 2 details"
},
{
"id":3,
"name":"Result3"
"details":"Result 3 details"
],
"caller":"1135345"
}
Does anybody have a clue how I can generate this piece of JSON using C# without having to load the entire Json.NET framework? I need this to be generated as fast as possible as this project aims to become an site search engine.
You should look at using the JavaScriptSerializer. It's part of the .NET framework (distributed in System.Web.Extensions). To get the result you want you can do this:
var results = new[]
{
new{id=1,name="Result 1"},
new{id=2,name="Result 2"},
new{id=3,name="Result 3"}
};
var js = new JavaScriptSerializer();
var result = js.Serialize(new
{
status = "ok",
response = results,
caller = 1135345
});
You can either use anonymous classes, or any existing ones. Works perfectly fine :)
The return value of this call would be:
{"status":"ok","response":[{"id":1,"name":"Result 1"},{"id":2,"name":"Result 2"},{"id":3,"name":"Result 3"}],"caller":1135345}
Using the JavaScriptSerializer rather than DataContractJsonSerializer on a Dictionary will remove the Key/Value json attributes and make them into a "keyed" array.
http://msdn.microsoft.com/en-us/library/bb412168.aspx
Have you attributed your classes with the [DataContract] and [DataMember] decorators?
http://msdn.microsoft.com/en-us/library/bb412179.aspx

Categories

Resources