Parse JSON array with Json.net - c#

how can I read the JSON from this site (http://www.pegelonline.wsv.de/webservices/rest-api/v2/stations.json?includeTimeseries=true&includeCurrentMeasurement=true) in C# with the Json.net library?
In this JSon there is only a array. I tested it with this code, but it doesn't work.
using (Stream stream = response.GetResponseStream())
{
JsonReader reader = new JsonTextReader(new StreamReader(stream));
dynamic info = JObject.Load(reader);
}
If i debug this, then VS says that the item is not an object. I try it with JArray.Load(reader); but then I don't know how to access the items.

You are right, JArray.Load is working correctly. The JArray then has a simple indexer to get to the individual items:
using (Stream stream = response.GetResponseStream())
{
var reader = new JsonTextReader(new StreamReader(stream));
var jsonArray = JArray.Load(reader);
var item20 = jsonArray[19];
var item20ShortName = (string)item20["shortname"];
}

Related

How to read an unformatted json stream and write to a formatted json file with minimal memory usage?

I'm calling an API that return a response of type application/json. The response can be very tiny but it can be very huge, 500mb to 700mb. I would like to format the content (indentation, new lines, etc) and write the response to a json file with the help of System.Text.Json so the file can be read easely by an humain.
This code write the response stream directly to a file very efficiently on memory and speed but it doesn't format the json content. Since that the stream is directly written to the file, it doesn't take memory at all.
var response = await new HttpClient().GetAsync("an url", HttpCompletionOption.ResponseHeadersRead);
var responseStream = await response.Content.ReadAsStreamAsync();
using (var fileStream = File.Open(filePath, FileMode.Create))
{
await responseStream.CopyToAsync(fileStream);
}
I tried this code to add the formatting but it doesn't seems right since that it use over 1gb of memory.
var response = await new HttpClient().GetAsync("an url", HttpCompletionOption.ResponseHeadersRead);
var responseStream = await response.Content.ReadAsStreamAsync();
var jsonDocument = System.Text.Json.JsonDocument.Parse(responseStream);
var jsonWriterOptions = new System.Text.Json.JsonWriterOptions()
{
Indented = true
};
using (var fileStream = File.Open(filePath, FileMode.Create))
using (var jsonTextWriter = new System.Text.Json.Utf8JsonWriter(fileStream, jsonWriterOptions))
{
jsonDocument.WriteTo(jsonTextWriter);
}
Is there a more optimized way, that use less memory, to deal with huge content?
It seems that there's no easy way to do it with System.Text.Json because you cannot use a Stream object with the System.Text.Json.Utf8JsonReader directly. To bypass this limitation, you need to put the file content into memory with the System.Text.Json.JsonDocument object so obviously, it will take up a lot of memory.
For now, with what a read on the web, the only solution that is memory efficient is to use Newtonsoft.Json library. Since that there's no parsing involved with this logic, no memory is used to make the conversion.
In this example, the stream come from an HttpClient response.
var response = await new HttpClient().GetAsync("an url", HttpCompletionOption.ResponseHeadersRead);
var responseStream = await response.Content.ReadAsStreamAsync();
using (var streamReader = new StreamReader(responseStream))
using (var jsonReader = new JsonTextReader(streamReader))
using (var streamWriter = File.CreateText(destinationFilePath))
using (var jsonTextWriter = new JsonTextWriter(streamWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
while (jsonReader.Read())
{
jsonTextWriter.WriteToken(jsonReader);
}
}
This example show how to read an existing file
using (var streamReader = new StreamReader(sourceFilePath))
using (var jsonReader = new JsonTextReader(streamReader))
using (var streamWriter = File.CreateText(destinationFilePath))
using (var jsonTextWriter = new JsonTextWriter(streamWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
while (jsonReader.Read())
{
jsonTextWriter.WriteToken(jsonReader);
}
}

Newtonsoft.Json to System.Text.Json StreamReader equivalent

What's the equivalent to this in System.Text.Json?
System.IO.Stream stream;
using (var streamReader = new StreamReader(stream))
{
using (var jsonTextReader = new JsonTextReader(streamReader))
{
var jsonSerializer = new JsonSerializer();
return jsonSerializer.Deserialize<T>(jsonTextReader);
}
}
This is as far as I got:
using (var streamReader = new StreamReader(stream))
{
using (var jsonTextReader = new Utf8JsonReader(streamReader))
{
return JsonSerializer.Deserialize<T>(jsonTextReader);
}
}
Utf8JsonReader doesn't have an option for a stream reader...
Since .NET 6 JsonSerializer.Deserialize has an overload accepting Stream, so you can deserialize from Stream directly (assuming that the stream is encoded in UTF-8):
return JsonSerializer.Deserialize<T>(stream);

Deserialize multiple json objects from a stream using Newtonsoft Json

I am reading a NetworkStream for json string and then deserializing it using Newtonsoft.Json.
Sometimes, two json objects could be sent back-to-back and read at the same time on the stream. But the Newtonsoft.Json serializer gives me only one object.
For example, if I have the following string on the stream:
{"name":"John Doe","age":10}{"name":"Jane Doe","age":10}
If I deserialize the stream, the serializer reads the entire stream, but gives only the first object.
Is there a way to make the serializer read only the first object from the stream and then read the next object in the next iteration of a loop?
Code:
public static Person Deserialize(Stream stream)
{
var Serializer = new JsonSerializer();
var streamReader = new StreamReader(stream, new UTF8Encoding());
return Serializer.Deserialize<Person>(new JsonTextReader(streamReader));
}
I cannot deserialize as a list because I'm not receiving a json array.
I think you can do it like this:
public static IList<Person> Deserialize(Stream stream) {
var serializer = new JsonSerializer();
var streamReader = new StreamReader(stream, new UTF8Encoding());
var result = new List<Person>();
using (var reader = new JsonTextReader(streamReader)) {
reader.CloseInput = false;
// important part
reader.SupportMultipleContent = true;
while (reader.Read()) {
result.Add(serializer.Deserialize<Person>(reader));
}
}
return result;
}
Important part is SupportMultipleContent property, which notifies reader that there might be multiple json objects side to side.
you can try it doing like this
var httpRequest = HttpContext.Current.Request;
// This list will have all the stream objects
var persons = new List<Person>();
if (httpRequest.Files.Count > 0)
{
for (var obj = 0; doc < httpRequest.Files.Count; obj++)
{
var postedFile = httpRequest.Files[obj];
var bytes = new byte[postedFile.ContentLength];
postedFile.InputStream.Read(bytes, 0, postedFile.ContentLength);
persons.Add(Serializer.Deserialize<Person>(new JsonTextReader(new StreamReader(new MemoryStream(bytes)))));
}
}

Deserialise JSON file from disk directly to object

I'm trying to deserialise a JSON file from local disk into an object. I've got the following, but this only seems to work when downloading it from the web:
var client = new HttpClient();
using (var s = await client.GetStreamAsync(filePath))
using (var sr = new StreamReader(s))
using (var jr = new JsonTextReader(sr))
{
var js = new JsonSerializer();
return js.Deserialize<MyObject>(jr);
}
I'm trying to find a way to do this, without first reading it into a string.
From Here
you can deserialize an object from file in two way.
Solution-1: Read file into a string and deserialize JSON to a type
string json = File.ReadAllText(#"c:\myObj.json");
MyObject myObj = JsonConvert.DeserializeObject<MyObject>(json);
Solution-2: Deserialize JSON directly from a file
using (StreamReader file = File.OpenText(#"c:\myObj.json"))
{
JsonSerializer serializer = new JsonSerializer();
MyObject myObj2 = (MyObject)serializer.Deserialize(file, typeof(MyObject));
}
You can download Newtonsoft.Json from NuGet by following command
Install-Package Newtonsoft.Json
using (var s = new StreamReader(filePath))
{
using (var jr = new JsonTextReader(s))
{
var js = new JsonSerializer();
var obj = js.Deserialize<MyObject>(jr);
return obj;
}
}
You might want to look at this : https://msdn.microsoft.com/en-us/library/bb412179(v=vs.110).aspx
It's an MSDN article called "How to: Serialize and Deserialize JSON Data"

Using DataContractJsonSerializer to create a Non XML Json file

I want to use the DataContractJsonSerializer to serialize to file in JsonFormat.
The problem is that the WriteObjectmethod only has 3 options XmlWriter, XmlDictionaryWriter and Stream.
To get what I want I used the following code:
var js = new DataContractJsonSerializer(typeof(T), _knownTypes);
using (var ms = new MemoryStream())
{
js.WriteObject(ms, item);
ms.Position = 0;
using (var sr = new StreamReader(ms))
{
using (var writer = new StreamWriter(path, false))
{
string jsonData = sr.ReadToEnd();
writer.Write(jsonData);
}
}
}
Is this the only way or have I missed something?
Assuming you're just trying to write the text to a file, it's not clear why you're writing it to a MemoryStream first. You can just use:
var js = new DataContractJsonSerializer(typeof(T), _knownTypes);
using (var stream = File.Create(path))
{
js.WriteObject(stream, item);
}
That's rather simpler, and should do what you want...
I am actually quite terrified to claim to know something that Jon Skeet doesn't, but I have used code similar to the following which produces the Json text file and maintains proper indentation:
var js = new DataContractJsonSerializer(typeof(T), _knownTypes);
using (var stream = File.Create(path))
{
using (var writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, true, true, "\t"))
{
js.WriteObject(writer, item);
writer.Flush();
}
}
(as suggested here.)

Categories