How to use JsonTextReader twice - c#

I am given a stream of json data which contains a field named "type". This type field describes the type of object that needs to be created at runtime. It looks like I am unable to use the JsonTextReader twice and I cannot find away to reset the text reader to the beginning.
using (var streamReader = new StreamReader(stream, Encoding))
using (var jsonTextReader = new JsonTextReader(streamReader))
{
JToken token = JObject.Load(jsonTextReader);
var type = (string) token.SelectToken("type");
var modelType = Type.GetType("Project." + type + ", Project");
// Fails here
var obj = serializer.Deserialize(jsonTextReader, modelType);
}
I get this error message.
Unexpected token while deserializing object: EndObject.

You can create a JsonReader from the JToken.
JsonReader reader = token.CreateReader();

To reset your reader to the begginning, set the Position property of the underlying stream to 0.
streamReader.BaseStream.Position = 0;
Edit:
While this will reset your underlying stream, the jsonTextReader is forward-only by definition, which means its line number and position are readonly. For this to work you would have to reset the streamReader position, then feed it into a new JsonTextReader object.
So unfortunately Phil, there is no way to read the JsonTextReader twice since it is forward-only.
Reference:
http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonTextReader.htm
"Represents a reader that provides fast, non-cached, forward-only access to serialized Json data."

I cover using the JsonTextReader in a memory-efficient format, avoiding the Large Object Heap, etc., in my blog, as per James Newton King's recommendations. You can leverage this and the supplied code to read your JSON multiple times without worrying about the underlying implementation of JsonTextReader.
Comments and feedback always welcome.

I did some more testing and found that the following works.
Set JsonTextReader.CloseInput = false
Destroy the JsonTextReader (by closing the using statement)
Set StreamReader.BaseStream.Position = 0
Create a new JsonTextReader
It would look something like this:
using (var streamReader = new StreamReader(stream, encoding))
{
Type modelType = null;
using (var jsonTextReader = new JsonTextReader(streamReader))
{
jsonTextReader.CloseInput = false;
JToken token = JObject.Load(jsonTextReader);
string type = (string)token.SelectToken("type");
modelType = Type.GetType("Project." + type + ", Project");
}
streamReader.BaseStream.Position = 0;
using (var jsonTextReader = new JsonTextReader(streamReader))
{
var obj = serializer.Deserialize(jsonTextReader, modelType);
}
}

Related

Mongodb.Bson BsonBinaryWriter can't write field with name

I'm trying to write int value to BsonBinaryWriter using WriteInt32, but receive exception "WriteName can only be called when State is Name, not when State is Initial".
code sample
using MongoDB.Bson;
using MongoDB.Bson.IO;
BsonBinaryWriter writer = new BsonBinaryWriter(new MemoryStream());
writer.WriteInt32("t", 1); // receive exception here
you should call WriteStartDocument first since what you're doing is creating a BSON document. So you're trying to add t : 1 value, but given that BSON document should roughly speaking correspond to JSON rules, you should open a bracket { (via WriteStartDocument) and close it at the end of a document (via WriteEndDocument).
See:
using var memoryStream = new MemoryStream();
using var writer = new BsonBinaryWriter(memoryStream);
writer.WriteStartDocument();
writer.WriteInt32("t", 1); // receive exception here
writer.WriteEndDocument();
memoryStream.Position = 0;
using var reader = new BsonBinaryReader(memoryStream);
var context = BsonDeserializationContext.CreateRoot(reader);
var document = BsonDocumentSerializer.Instance.Deserialize(context);
Console.WriteLine(document.ToString()); // => { "t" : 1 }

Convert a Stream into json value c#

I have below stream which I get from this line where req1 is of HttpResponseMessage type and responseMessage is of type Stream. How can I convert this Stream into a json Object. My end goal is to extract values from the specific keys in this json.
var responseMessage = await req1.Content.ReadAsStreamAsync();
Above answer has a class defined. I didnt want to define different class as my model is dynamic. I found this solution , which worked well and got me the desired result
var serializer = new JsonSerializer();
using (var sr = new StreamReader(responseMessage))
using (var jsonTextReader = new JsonTextReader(sr))
{
var jsObj= serializer.Deserialize(jsonTextReader);
}
try it
// read file into a string and deserialize JSON to a type
Movie movie1 = JsonConvert.DeserializeObject<Movie>(File.ReadAllText(#"c:\movie.json"));
// deserialize JSON directly from a file
using (StreamReader file = File.OpenText(#"c:\movie.json"))
{
JsonSerializer serializer = new JsonSerializer();
Movie movie2 = (Movie)serializer.Deserialize(file, typeof(Movie));
}

JsonDocument Get JSON String

I need an example of getting a JSON string from a JsonDocument. I can get properties with RootElement.GetProperty("ItemName") and then call .GetString() but can't see a way to just get the root element as a JSON string?
Here an example:
JsonDocument jdoc = JsonDocument.Parse("{\"a\":123}");
using(var stream = new MemoryStream())
{
Utf8JsonWriter writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true });
jdoc.WriteTo(writer);
writer.Flush();
string json = Encoding.UTF8.GetString(stream.ToArray());
}
For an easier usage you could put it in an extension method like:
public static string ToJsonString(this JsonDocument jdoc)
{
using (var stream = new MemoryStream())
{
Utf8JsonWriter writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true });
jdoc.WriteTo(writer);
writer.Flush();
return Encoding.UTF8.GetString(stream.ToArray());
}
}
And use it like:
JsonDocument jdoc = JsonDocument.Parse("{\"a\":123}");
string json = jdoc.ToJsonString();
I have use RootElement to get a JsonElement and then call .ToString().
JsonDocument jdoc = JsonDocument.Parse("{\"a\":123}");
string json = jdoc.RootElement.ToString();
For the record there are 2 code snippets in official doco at How to serialize and deserialize (marshal and unmarshal) JSON in .NET
A. Use JsonDocument to write JSON
The following example shows how to write JSON from a JsonDocument:
(surprisingly long code snippet here)
The preceding code:
Reads a JSON file, loads the data into a JsonDocument, and writes formatted (pretty-printed) JSON to a file.
Uses JsonDocumentOptions to specify that comments in the input JSON are allowed but ignored.
When finished, calls Flush on the writer. An alternative is to let the writer autoflush when it's disposed.
B. Use Utf8JsonWriter
The following example shows how to use the Utf8JsonWriter class:
(...)
The snipped can be adjusted to use JsonDocument.Parse:
using var stream = new System.IO.MemoryStream();
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
{
var jsonDocument = JsonDocument.Parse(content);
jsonDocument.WriteTo(writer);
}
var formatted = System.Text.Encoding.UTF8.GetString(stream.ToArray());

Deserialize Dictionary<> using DataContractSerializer

I need to deserialize Dictionary<> in C#. Since, XmlSerializer cannot be used for generic Dictionary type, I thought of using DataContractSerializer.I had a StreamReader in which the data was to be deserialized, but it showed unmatching overload parameters on using with DataContractSerializer.ReadObject.
My previous code was:
StreamReader isr = new StreamReader(File.OpenRead(algorithmName + ".conf"));
configuration.Load(isr);
The Load method is defined as:
public void Load(StreamReader isr)
{
DataContractSerializer dcs = new DataContractSerializer(typeof(the class containing this method));
XmlDictionaryReader read = XmlDictionaryReader.CreateTextReader(isr, new XmlDictionaryReaderQuotas());
dcs.ReadObject(isr);
}
The Load method is contained in class that implements Dictionary<>
But this showed parameter mismatched error due to StreamReader as parameter for ReadObject().
So, I modified the code as:
FileStream isr = File.OpenRead(algorithmName + ".conf");
configuration.Load(isr);
And the Load method as:
public void Load(FileStream isr)
{
DataContractSerializer dcs = new DataContractSerializer(typeof(the class containing Load method));
XmlDictionaryReader read = XmlDictionaryReader.CreateTextReader(isr, new XmlDictionaryReaderQuotas());
dcs.ReadObject(isr);
}
Now there are no errors but I wanted to know whether using DataContractSerializer in place of XmlSerializer is correct or not. Also, any updates on replacing streamreader with filestream would be highly appreciated.

How to use XSLT to transform XML output of DataContractSerializer

I have become confused due to all of the samples using DataContractSerializer only handling one single object. I have a collection of objects, let's call it List<Ticket> tickets. I can get a the DataContractSerializer to write each object using a foreach (var ticket in tickets), but afterward I need to run a transform on the XML in order to be sure it is properly formatted. However, when using the Transform method of a XmlCompiledTransform I continue receiving the error "Unexpected end of file while parsing Name has occurred. Line 447, position 28."
Below is my code, all constructive criticism is welcome.
using (var ms = new MemoryStream())
{
using (var writer = XmlWriter.Create(ms, settings))
{
var ser = new DataContractSerializer(tickets.GetType());
writer.WriteStartDocument(true);
writer.WriteStartElement("Tickets");
foreach (var ticket in tickets)
{
ser.WriteObject(writer, ticket);
}
writer.WriteEndElement();
writer.WriteEndDocument();
ms.Position = 0;
var xslt = new XslCompiledTransform();
xslt.Load(xsltFp);
using (var output = new FileStream(xmlFp, FileMode.Create))
{
xslt.Transform(XmlReader.Create(ms), null, output);
output.Position = 0;
}
}
}
I figured it out. At the end of the foreach loop, I needed to call writer.Flush();. This effectively flushes the stream buffer before we start writing another object.

Categories