I am trying to get value of label from following string.
I have a string in this format.
var string = "[{\"key\":\"182\",\"label\":\"testinstitution\"}]"
dynamic dict = new JavaScriptSerializer().Deserialize<dynamic>(string);
string inst = dict["label"]; //This is not working
I am getting dict in form of key value pair object but I am not able to get value of label. I cannot use JSON.NET.
To retrieve value of label from your string use string inst = dict[0]["label"];.
Explanation
The reason why you need additional [0] is because deserialization returns array of key value pairs. First object from that array will go to index [0], second object from array to index [1] an so on. Your string has array of only one object. Here is an example of when you have two objects, where second object has another object inside of it, in which case you would have to write dict[1]["foo"]["two"] to get to desired value:
var myString = #"
[
{
'one': '1'
},
{
'foo':
{
'two': '2'
}
}
]";
dynamic dict = new JavaScriptSerializer().Deserialize<dynamic>(myString);
string inst = dict[1]["foo"]["two"];
Additional FYI
If you know structure of your data consider using strong types (as suggested in one of the comments). Here is example of how you would do it:
public class Data
{
public string key { get; set; }
public string label { get; set; }
}
class Program
{
static void Main(string[] args)
{
var myString = #"
[{
'key': 182,
'label': 'testinstitution'
}]";
List<Data> dict = new JavaScriptSerializer().Deserialize<List<Data>>(myString);
foreach (var d in dict)
Console.WriteLine(d.key + " " + d.label);
Console.ReadKey();
}
}
Note that properties key and value in your Data object much match names of those in your array of objects exactly.
Related
In C#, I want to replace the string Placeholder with Object Properties using Reflection
string formula = "{\"Name\": \"{{Name}}\", \"Email\": \"{{Email}}\" }";
Student student = new Student();
student.Name = "Parker";
student.Email = "Parker#xyz.com";
student.Address = "Mark Avenue";
var result1 = GenerateJson(formula, student);
//Output : "{\"Name\": \"Parker\", \"Email\": \"Parker#xyz.com\" }"
student.Name = "Royal";
student.Email = "Royal#xyz.com";
student.Address = "Cross Lane";
var result2 = GenerateJson(formula, student);
//Output : "{\"Name\": \"Royal\", \"Email\": \"Royal#xyz.com\" }"
public string GenerateJson(string formula, Student student)
{
string result = "";
//logic for replacing the Placeholder woth object properties
return result;
}
class Student
{
public string Name { get; set; }
public string Email { get; set; }
public string Address { get; set; }
}
If you really don't want or cannot use Json.NET than you can try solution below
public string GenerateJson(string formula, Student student)
{
return Regex.Replace(formula, #"\{\{(\w+)\}\}", match => typeof(Student).GetProperty(
match.Groups[1].ToString())?.GetValue(student)?.ToString());
}
You can deserialize it to ExpandoObject (IDictionary<string,object>). Then compare property names with the known type. If there is match between Dictionary's key and student's propertyName. Replace ExpandoObject's Value with Student's property's value. After all, serialize it to json.
Here it is,
public string GenerateJson(string formula, Student student)
{
IDictionary<string, object> templateValues = JsonConvert.DeserializeObject<IDictionary<string, object>>(formula);
PropertyInfo[] sourceProperty = typeof(Student).GetProperties();
foreach (var item in sourceProperty)
{
KeyValuePair<string,object> value = templateValues.FirstOrDefault(x=> x.Key == item.Name);
if (value.Key != null)
{
templateValues[item.Name] = item.GetValue(student);
}
}
return JsonConvert.SerializeObject(templateValues);
}
It looks like the actual problem is retrieving the value of specific properties to generate an API signature. It's unclear if the signature to sign really needs to be a JSON string or not.
The easiest way is to create an anonymous type with the necessary properties and serialize it, eg :
var payload=JsonConvert.Serialize(new {student.Name,student.Email});
This is far faster than any reflection code and allocates a single extra object only. If you want to use an API with a lot of different request types, it pays to use a code generator or in C# 9, a source generator to generate such calls.
It's possible (but slow) to use reflection to retrieve specific properties, eg with :
var dict=typeof(Student).GetProperties()
.Where(prop=>myProps.Contains(prop.Name))
.ToDictionary(prop=>prop.Name,prop=>prop.GetValue(student));
var json=JsonConvert.Serialize(dict);
A JSON object is actually a dictionary, so serializing a dictionary behaves similarly to serializing an object with the same properties.
Reflection is relatively expensive though, so it's a good idea to cache the PropertyInfo objects you want and reuse them:
Dictionary<Type,PropertyInfo[]> _properties=new Dictionary<Type,PropertyInfo[]>();
...
string GenerateJson<T>(T item)
{
PropertyInfo[] props;
if (!_properties.TryGetValue(typeof(T),out props))
{
props=typeof(Student).GetProperties()
.Where(prop=>myProps.Contains(prop.Name))
.ToArray();
}
var dict=props.ToDictionary(prop=>prop.Name,prop=>prop.GetValue(item));
return JsonConvert.Serialize(dict);
}
I need to convert to dictionary JSON array of objects with key "id" and value "score" properties like the following
[{"score":0.6990418,"id":"4833909335"},
{"score":0.8079009,"id":"4833874639"},
{"score":0.8079009,"id":"4834247506"}].
Dictionary keys should have values of "id" property, and dictionary values shoud be copied from "score".
Note that it is not a deserialization, but transforming/mapping when some information not copied to target object(e.g. names of properties and potentially other properties)
I found similar question How to deserialize the json array of objects to dictionary , that was incorrectly closed as duplicate of different question about deserializing different JSON object with multiple properties.
I've tried to reopen it, but without success.
I've created extension methods to allow extract pair of properties from elements of JSON array
public static Dictionary< string, string> JsonArrayToDictionary( string strJson, string keyName,string valueName)
{
var array = JArray.Parse(strJson) ;
var dictionary = JsonArrayToDictionary(array, keyName, valueName);
return dictionary;
}
public static Dictionary<string , string > JsonArrayToDictionary(this JArray array, string keyName, string valueName)
{
if (array != null)
{
var dict = array.ToDictionary(x => x[keyName].ToString(), x => x[valueName].ToString());
return dict;
}
return null;
}
[TestClass()]
public class JsonHelperExtensionsTests
{
[ TestMethod()]
public void JsonArrayToDictionaryTest()
{
var jsonArray= #"[{""score "":0.6990418,"" id"": ""ID1"" },{""score "":0.8079009,"" id"": ""ID2"" }]";
var dict= JsonHelperExtensions.JsonArrayToDictionary(jsonArray, "id" , "score");
dict.Count.Should().Be(2);
dict[ "ID1"].Should().Be("0.6990418" );
}
}
Current solution for current time:
var jsArray = JObject.Parse(response);
var arrayDictionary = JsonConvert.DeserializeObject<Dictionary<string, dynamic>[]>(jsArray.ToString());
I need to convert JSON data that I get from a REST API and convert them to CSV for some analytic. The problem is that the JSON data do not necessarily follow the same content, so I can't define a type for mapping. This has become a challenge that is taking too much of my time. I have already created some code, but of course it is not working as it throws exception on this line
var data = JsonConvert.DeserializeObject<List<object>>(jsonData);
The error is:
Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type
'System.Collections.Generic.List`1[System.Object]' because the type
requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'data', line 2, position 10.
please let me know what I can do to get this going.
A sample of data would be like this, the fields of data can change very often, for example a new field can be added the next day, so I don't have the liberty to create a .Net class to map the data.
{
"data": [
{
"ID": "5367ab140026875f70677ab277501bfa",
"name": "Happiness Initiatives - Flow of Communication/Process & Efficiency",
"objCode": "PROJ",
"percentComplete": 100.0,
"plannedCompletionDate": "2014-08-22T17:00:00:000-0400",
"plannedStartDate": "2014-05-05T09:00:00:000-0400",
"priority": 1,
"projectedCompletionDate": "2014-12-05T08:10:21:555-0500",
"status": "CPL"
},
{
"ID": "555f452900c8b845238716dd033cf71b",
"name": "UX Personalization Think Tank and Product Strategy",
"objCode": "PROJ",
"percentComplete": 0.0,
"plannedCompletionDate": "2015-12-01T09:00:00:000-0500",
"plannedStartDate": "2015-05-22T09:00:00:000-0400",
"priority": 1,
"projectedCompletionDate": "2016-01-04T09:00:00:000-0500",
"status": "APR"
},
{
"ID": "528b92020051ab208aef09a4740b1fe9",
"name": "SCL Health System - full Sitecore implementation (Task groups with SOW totals in Planned hours - do not bill time here)",
"objCode": "PROJ",
"percentComplete": 100.0,
"plannedCompletionDate": "2016-04-08T17:00:00:000-0400",
"plannedStartDate": "2013-11-04T09:00:00:000-0500",
"priority": 1,
"projectedCompletionDate": "2013-12-12T22:30:00:000-0500",
"status": "CPL"
}
]
}
namespace BusinessLogic
{
public class JsonToCsv
{
public string ToCsv(string jsonData, string datasetName)
{
var data = JsonConvert.DeserializeObject<List<object>>(jsonData);
DataTable table = ToDataTable(data);
StringBuilder result = new StringBuilder();
for (int i = 0; i < table.Columns.Count; i++)
{
result.Append(table.Columns[i].ColumnName);
result.Append(i == table.Columns.Count - 1 ? "\n" : ",");
}
foreach (DataRow row in table.Rows)
{
for (int i = 0; i < table.Columns.Count; i++)
{
result.Append(row[i].ToString());
result.Append(i == table.Columns.Count - 1 ? "\n" : ",");
}
}
return result.ToString().TrimEnd(new char[] {'\r', '\n'});
}
private DataTable ToDataTable<T>( IList<T> data )
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0 ; i < props.Count ; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0 ; i < values.Length ; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
}
}
The real issue here is that you are trying to deserialize into a List<object> but your JSON actually represents a single object containing a data property which then contains a list of objects. That is why you are getting this error. Json.Net can't deserialize a single object into a list. I think what you really want to do is define a container class like this:
class Root
{
public List<Dictionary<string, object>> Data { get; set;}
}
Then deserialize like this:
var data = JsonConvert.DeserializeObject<Root>(jsonData).Data;
You will then end up with a list of dictionaries, where each dictionary represents one item in the JSON array. The dictionary key-value pairs are the dynamic values in each item. You can then work with these as you would with any other dictionary. For example, here is how you would dump out all the data:
foreach (var dict in data)
{
foreach (var kvp in dict)
{
Console.WriteLine(kvp.Key + ": " + kvp.Value);
}
Console.WriteLine();
}
Fiddle: https://dotnetfiddle.net/6UaKhJ
What you're looking for is the dynamic type. Though unrelated, this answer contains much of the information on how you'll be able to iterate through the changing properties on your object.
You will need to add some additional work to figure out how to handle your result when it is an array versus a single object as your error shows us. However, this is a good first step for you.
Basically, a dynamic object is a Dictionary, much like how a JSON object is treated in JavaScript. You just need to iterate through each of the KeyValuePair objects within the main object and go through their properties.
var data = JsonConvert.DeserializeObject<dynamic>(jsonData);
var rows = new List<string>();
// Go through the overall object, and get each item in
// the array, or property in a single object.
foreach (KeyValuePair<string, object> item in data)
{
dynamic obj = item.Value;
var row = "";
// Perhaps add a check here to see if there are more
// properties (if it is an item in an array). If not
// then you are working with a single object, and each
// item is a property itself.
foreach (KeyValuePair<string, object> prop in obj)
{
// Very dummy way to demo adding to a CSV
string += prop.Value.ToString() + ",";
}
rows.Add(string);
}
This is far from a complete example, but we don't have enough information to go on to help you finish what you're trying to do.
You are trying to deserialize into a List but your JSON actually represents a single object containing a data property containing list of objects. That is why you are getting this error. Json.Net can't deserialize a single object into a list.
Please try this:Create a class which contain single property on datatype Object and pass this class for deserialization.
class Parent
{
public object Data { get; set;}
}
Then deserialize like this:
var output = JsonConvert.DeserializeObject<Parent>(jsonData);
Try using this class instead of Object
public class Datum
{
public string ID { get; set; }
public string name { get; set; }
public string objCode { get; set; }
public double percentComplete { get; set; }
public string plannedCompletionDate { get; set; }
public string plannedStartDate { get; set; }
public int priority { get; set; }
public string projectedCompletionDate { get; set; }
public string status { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
}
Change to this:
var data = JsonConvert.DeserializeObject<RootObject>(jsonData);
If your data is dynamic so try a dynamic list:
using System.Web.Script.Serialization;
JavaScriptSerializer jss = new JavaScriptSerializer();
var d=jss.Deserialize<dynamic>(str);
Since you're trying to deserialize an object type into a list type, it won't deseralize directly.
You can do this:
var data = JsonConvert.DeserializeObject<ObjectDataList>(jsonData);
var rows = new List<DeserializedData>();
foreach (dynamic item in data)
{
var newData = new DeserializedData();
foreach (dynamic prop in item)
{
var row = new KeyValuePair<string, string>
(prop.Name.ToString(), prop.Value.ToString());
newData.Add(row);
}
rows.Add(newData);
}
Here are new classes
//class for key value type data
class DeserializedData
{
List<KeyValuePair<string, string>> NewData =
new List<KeyValuePair<string, string>>();
internal void Add(KeyValuePair<string, string> row)
{
NewData.Add(row);
}
}
[DataContract]
class ObjectDataList
{
[DataMember(Name ="data")]
List<object> Data { get; set; }
public IEnumerator<object> GetEnumerator()
{
foreach (var d in Data)
{
yield return d;
}
}
}
As far as I can tell, more recent versions of Newtonsoft can actually do this now, no additional work required.
I was working with the binary version however, and this did still have the issue - I had a test where you could configure to use binary or json, and the json version worked just fine, but the binary complained about not getting an array type.
I started using the BsonDataReader for this, and was looking through the properties and methods on it to see how I could best look at the contents, and lo and behold, this had a property called:
reader.ReadRootValueAsArray
Setting this to 'true' did the trick.
I have an incoming JSON, which consists array of some objects, say, Foo. I deserialize them with
result = JsonConvert.DeserializeObject<List<Foo>>(message);
Now i want to add a string property to Foo, which will store it's JSON (which i received), so that Foo'll look like:
public class Foo
{
public int MyInt { get; set; }
public bool MyBool { get; set; }
public string JSON { get; set; }
}
But i don't know how can i say JSON.Net the way it can populate such a field..
UPD
I'll clearify what i want. Say i receive JSON:
[{"MyInt":1,"MyBool":0},{"MyInt":2,"MyBool":0},{"MyInt":3,"MyBool":1}]
Here is array of 3 objects and i want, when deserializing, to add corresponding part of json to object, so that:
First object will contain {"MyInt":1,"MyBool":0}
Second object will contain {"MyInt":2,"MyBool":0}
Third object will contain {"MyInt":3,"MyBool":1}
in their JSON Property
I'll be gratefull for any help!
This is one way to do it, but it doesn't maintain the exact original JSON - but it does provide a static record of the original JSON (but without the exact format of the original values - i.e. Bool maybe be 0/1 or true/false):
var message = #"[{""MyInt"":1,""MyBool"":0},{""MyInt"":2,""MyBool"":0},{""MyInt"":3,""MyBool"":1}]";
var foos = JsonConvert.DeserializeObject<List<Foo>>(message);
var t = JsonConvert.SerializeObject(foos[0]);
foos = foos.Select(s => new Foo() { MyBool = s.MyBool, MyInt = s.MyInt, JSON = JsonConvert.SerializeObject(s) }).ToList();
If you are dealing with a lot of Foos, then you might want to find a more efficient way. There might be a way to 'update' using linq, rather than creating a new list.
Okay, i found an answer. I didn't know that i can deserialize message into JArray and then enumerate it (good job, newtonsoft:) ). Here is what i endede up with:
if (tokenType is JArray)
{
var arr = JsonConvert.DeserializeObject(message) as JArray;
foreach (var item in arr)
{
try
{
var agentParameter = item.ToObject<Foo>();
agentParameter.JSON = item.ToString();
result.Add(agentParameter);
}
catch (Exception)
{
LogProvider.Error(string.Format("Failed to Deserialize message. Message text: \r\n {0}", item.ToString()));
}
}
}
I would like to serialize a Dictionary to a JSON array with ASP.NET Web API. To illustrate the current output I have the following setup:
Dictionary<int, TestClass> dict = new Dictionary<int, TestClass>();
dict.Add(3, new TestClass(3, "test3"));
dict.Add(4, new TestClass(4, "test4"));
The TestClass is defined as follows:
public class TestClass
{
public int Id { get; set; }
public string Name { get; set; }
public TestClass(int id, string name)
{
this.Id = id;
this.Name = name;
}
}
When serialized to JSON I get the following output:
{"3":{"id":3,"name":"test3"},"4":{"id":3,"name":"test4"}}
Unfortunately this is an Object and not an Array. Is it somehow possible to achieve what I'm trying to do? It doesn't need to be a Dictionary but I need the Id's of the TestClass to be the Key's of the Array.
With the following List it is correctly serialized to an array but not with the correct Key's.
List<TestClass> list= new List<TestClass>();
list.Add(new TestClass(3, "test3"));
list.Add(new TestClass(4, "test4"));
Serialized to JSON:
[{"id":3,"name":"test3"},{"id":4,"name":"test4"}]
but I need the Id's of the TestClass to be the Key's of the Array.
In javascript what you call an array must be an object in which the indexes are 0-based integers. This is not your case. You have id 3 and 4 which cannot be used as indexes in a javascript array. So using a List is the correct approach here.
Because if you want to use arbitrary indexes (as in your case you have some integers that are not 0-based) this is no longer an array but an object in which those integers or strings are simply the properties of this object. That's what you achieve with the Dictionary.
You could convert the object to an array client-side using vanilla js.
var jsonFromServer = {"3":{"id":3,"name":"test3"},"4":{"id":4,"name":"test4"}};
var expected = [];
Object.keys(jsonFromServer).forEach(key => expected[+key] = json[key]);
console.log(expected.length); // 5
console.log(expected[0]); // undefined
console.log(expected[1]); // undefined
console.log(expected[2]); // undefined
console.log(expected[3]); // Object { id: 3, name: "test3" }
console.log(expected[4]); // Object { id: 4, name: "test4" }