loop on data returned after deserializing - c#

I get data from instagram api. So i use below
var responseStream = webRequest.GetResponse().GetResponseStream();
Encoding encode = System.Text.Encoding.Default;
using (StreamReader reader = new StreamReader(responseStream, encode))
{
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var jsonObject = serializer.DeserializeObject(reader.ReadToEnd());
}
I dont know how to loop on this data. I tried
foreach (var item in jsonObject)
{
}
But it gives compile time error Type object is not enumerable
How do i loop?

Your variable jsonObject is an object which is not an enumerable.
You must specify an enumerable type when deserializing :
var jsonObject = serialize.Deserialize<enumerableType>(reader.ReadToEnd());

Related

Serialising a collection is converting to a JObject rather than a JArray [duplicate]

I am simply trying to serialize and deserialize a string array in Bson format using Json.NET, but the following code fails:
var jsonSerializer = new JsonSerializer();
var array = new string [] { "A", "B" };
// Serialization
byte[] bytes;
using (var ms = new MemoryStream())
using (var bson = new BsonWriter(ms))
{
jsonSerializer.Serialize(bson, array, typeof(string[]));
bytes = ms.ToArray();
}
// Deserialization
using (var ms = new MemoryStream(bytes))
using (var bson = new BsonReader(ms))
{
// Exception here
array = jsonSerializer.Deserialize<string[]>(bson);
}
Exception message:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.String[]' 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.
How can I get this to work?
Set ReadRootValueAsArray to true on BsonReader
http://james.newtonking.com/projects/json/help/index.html?topic=html/P_Newtonsoft_Json_Bson_BsonReader_ReadRootValueAsArray.htm
This setting is required because the BSON data spec doesn't save metadata about whether the root value is an object or an array.
Hmmm, from where I sit, your code should work, but Json.Net seems to think that your serialized array of strings is a dictionary. This could be because, according to the BSON specification, arrays actually do get serialized as a list of key-value pairs just like objects do. The keys in this case are simply the string representations of the array index values.
In any case, I was able to work around the issue in a couple of different ways:
Deserialize to a Dictionary and then manually convert it back to an array.
var jsonSerializer = new JsonSerializer();
var array = new string[] { "A", "B" };
// Serialization
byte[] bytes;
using (var ms = new MemoryStream())
using (var bson = new BsonWriter(ms))
{
jsonSerializer.Serialize(bson, array);
bytes = ms.ToArray();
}
// Deserialization
using (var ms = new MemoryStream(bytes))
using (var bson = new BsonReader(ms))
{
var dict = jsonSerializer.Deserialize<Dictionary<string, string>>(bson);
array = dict.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToArray();
}
Wrap the array in an outer object.
class Wrapper
{
public string[] Array { get; set; }
}
Then serialize and deserialize using the wrapper object.
var jsonSerializer = new JsonSerializer();
var obj = new Wrapper { Array = new string[] { "A", "B" } };
// Serialization
byte[] bytes;
using (var ms = new MemoryStream())
using (var bson = new BsonWriter(ms))
{
jsonSerializer.Serialize(bson, obj);
bytes = ms.ToArray();
}
// Deserialization
using (var ms = new MemoryStream(bytes))
using (var bson = new BsonReader(ms))
{
obj = jsonSerializer.Deserialize<Wrapper>(bson);
}
Hope this helps.
As explained in this answer by James Newton-King, the BSON format doesn't save metadata about whether the root value is a collection, making it necessary to set BsonDataReader.ReadRootValueAsArray appropriately before beginning to deserialize.
One easy way to do this, when deserializing to some known POCO type (rather than dynamic or JToken), is to initialize the reader based on whether the root type will be serialized using an array contract. The following extension methods do this:
public static partial class BsonExtensions
{
public static T DeserializeFromFile<T>(string path, JsonSerializerSettings settings = null)
{
using (var stream = new FileStream(path, FileMode.Open))
return Deserialize<T>(stream, settings);
}
public static T Deserialize<T>(byte [] data, JsonSerializerSettings settings = null)
{
using (var stream = new MemoryStream(data))
return Deserialize<T>(stream, settings);
}
public static T Deserialize<T>(byte [] data, int index, int count, JsonSerializerSettings settings = null)
{
using (var stream = new MemoryStream(data, index, count))
return Deserialize<T>(stream, settings);
}
public static T Deserialize<T>(Stream stream, JsonSerializerSettings settings = null)
{
// Use BsonReader in Json.NET 9 and earlier.
using (var reader = new BsonDataReader(stream) { CloseInput = false }) // Let caller dispose the stream
{
var serializer = JsonSerializer.CreateDefault(settings);
//https://www.newtonsoft.com/json/help/html/DeserializeFromBsonCollection.htm
if (serializer.ContractResolver.ResolveContract(typeof(T)) is JsonArrayContract)
reader.ReadRootValueAsArray = true;
return serializer.Deserialize<T>(reader);
}
}
}
Now you can simply do:
var newArray = BsonExtensions.Deserialize<string []>(bytes);
Notes:
BSON support was moved to its own package, Newtonsoft.Json.Bson, in Json.NET 10.0.1. In this version and later versions BsonDataReader replaces the now-obsolete BsonReader.
The same extension methods can be used to deserialize a dictionary, e.g.:
var newDictionary = BsonExtensions.Deserialize<SortedDictionary<int, string>>(bytes);
By checking the contract type ReadRootValueAsArray is set appropriately.
Demo fiddle here.
In general, you could check data type first before set ReadRootValueAsArray to true, like this:
if (typeof(IEnumerable).IsAssignableFrom(type))
bSonReader.ReadRootValueAsArray = true;
I know this is an old thread but I discovered a easy deserialization while using the power of MongoDB.Driver
You can use BsonDocument.parse(JSONString) to deserialize a JSON object so to deserialize a string array use this:
string Jsonarray = "[\"value1\", \"value2\", \"value3\"]";
BsonArray deserializedArray = BsonDocument.parse("{\"arr\":" + Jsonarray + "}")["arr"].asBsonArray;
deserializedArray can then be used as any array such as a foreach loop.

C# convert JSON to a JArray for an upload to Algolia

With the Algolia online cloud search engine their examples work fine.
// Load JSON file ( from file system )
StreamReader re = File.OpenText("contacts.json");
JsonTextReader reader = new JsonTextReader(re);
JArray batch = JArray.Load(reader);
// Add objects
Index index = client.InitIndex("contacts");
index.AddObjects(batch);
So what I am wanting to do it take C# class of properties that I serialized to JSON and be able to somehow use it as a JArray to load and add to send to Algolia.
// works fine
var json = new JavaScriptSerializer().Serialize(boom);
JArray batch = JArray.Parse(json); // breaks
Index index = client.InitIndex("myindex");
index.AddObjects(batch);
This breaks
JArray batch = JArray.Parse(json);
It's most likely failing because boom is not an array. What you can do is put boom in an anonymous array, and serialize that instead:
var json = new JavaScriptSerializer().Serialize(new[] { boom });
var batch = JArray.Parse(json);
Even better, you can skip over the serialization and create the JArray immediately from your object:
var batch = JArray.FromObject(new[] { boom });

Using Linq to convert KeyValue pairs into Newtonsoft.Json.Linq.JObject

I am trying to use C# LINQ to build a JObject. I know that I can use a loop, such as,
var jobj = new JObject();
foreach (var field in fieldList)
{
jobj[field.Name] = new JValue(field.Value);
}
Is it possible to replace the loop with LINQ? I tried this,
var data = fieldList.Select(field => new KeyValuePair<string, JValue>(field.Name, new JValue(field.Value)));
var jobj = new JObject(data);
but it fails with this error:
Could not determine JSON object type for type System.Collections.Generic.KeyValuePair`2[
System.String,Newtonsoft.Json.Linq.JValue].
Here
jobj[field.Name] = new JValue(field.Value);
you actually are calling the following JObject indexer:
public JToken this[string propertyName] { get; set; }
i.e. you are setting the JObject property.
So the LINQ equivalent will be like this:
var data = fieldList.Select(field => new JProperty(field.Name, field.Value));
var jobj = new JObject(data);
Well, I don't know if it's any prettier, but you could use Aggregate:
fieldList.Aggregate(new JObject(), (obj, next) => {obj[next.Name] = new JValue(next.Value); return obj;})
It would be nice if JObject had a chainable API, but it doesn't seem to.

Cannot retrieve the key and Value info from the deserialized data

dynamic data = JsonConvert.DeserializeObject(result);
foreach (var field in data)
{
var deserializedData = new DeserializedData
{
Label = field.Key.ToObject<string>(),
Content = field.Value.ToObject<string>()
};
}
Note: data = {"name":"test"}
Error:'Newtonsoft.Json.Linq.JProperty' does not contain a definition for 'Key'
I think I understand what the issue is but I am not sure if there is a way to achieve this behavior or is there a different approach to handle the dynamic key value scenarios like this.
The Key will change so I don't know if its going to be name or phone or email or some other field...
In order to iterate through the children of the returned data as an IEnumerable<KeyValuePair<string, JToken>>, you need to explicitly declare the deserialized object as a JObject:
var data = JObject.Parse(result);
foreach (var field in data)
{
var deserializedData = new DeserializedData
{
Label = field.Key,
Content = field.Value.ToObject<string>()
};
}
When you do dynamic data = JsonConvert.DeserializeObject(result);, the foreach ends up calling the IEnumerable<JToken> iterator in the base class JToken. I.e. the following also works:
dynamic data = JsonConvert.DeserializeObject(result);
foreach (var field in data)
{
// "field" happens to be of type JProperty
var deserializedData = new DeserializedData
{
Label = field.Name,
Content = field.Value.ToObject<string>()
};
}
Though I prefer the strongly typed version using JObject since more checking can be done at compile time.
According to the documentation the JProperty's value contains the key, and the JProperty's children are the values. source

Converting wikipedia api response using Json.net

I'm querying data using wikipedia api and would like to convert the result into a string[].
The query "test"
en.wikipedia.org/w/api.php?action=opensearch&search=test&format=json&callback=spellcheck
returns this result here:
spellcheck(["test",["Test cricket","Test","Testicle","Testudines","Testosterone","Test pilot","Test (assessment)","Testimonial match","Testimony","Testament (band)"]])
Can I use Json.net to drop or ignore the tag "spellcheck"?
If I convert the response using this code, the application crashes:
Dictionary<string, string[]> dict = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(response);
Wikipedia's api (using JSON) assumes you're using JSONP. You could just drop the callback parameter completely from your query string:
en.wikipedia.org/w/api.php?action=opensearch&search=test&format=json
Additionally, the result you're getting probably cannot be converted into a Dictionary<string, string[]>. If you look closely, it's actually an array where the first object is a string (search term) and the second is a list of strings (results).
The following worked for me:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(
#"http://en.wikipedia.org/w/api.php?action=opensearch&search=test&format=json");
string[] searchResults = null;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
JArray objects = JsonConvert.DeserializeObject<JArray>(reader.ReadToEnd());
searchResults = objects[1].Select(j => j.Value<string>()).ToArray();
}
}

Categories

Resources