JsonSerializer can't read stream from StreamReader - c#

I can't get the DataContractJsonSerializer object to swallow my stream. When I execute the code with the commented-out line active, I get to see the text provided (and it is a parsable JSON object), so I know that the stream is working fine.
However, for some reason, the compiler complains that the streamReader I'm trying to shove down its throat in ReadObject isn't a Stream. Well, isn't it?!
Argument 1: cannot convert from 'System.IO.StreamReader' to 'System.IO.Stream'
What am I missing and how do I resolve it?
using (StreamReader streamReader = new StreamReader(...))
{
//String responseText = reader.ReadToEnd();
MyThingy thingy = new MyThingy();
DataContractJsonSerializer serializer
= new DataContractJsonSerializer(thingy.GetType());
thingy = serializer.ReadObject(streamReader);
}
I'm adapting this example to work with my stream. Should I approach it from a different angle? If so - how?

You're trying to put in a reader of a stream instead of an actual stream. Skip the using and whatever hides behind the ellipsis (i.e. whatever you put in as an argument when you create an instance of StreamReader), you can probably put that into the ReadObject.
Also, you'll get into problems when reading the data because ReadObject will return an instance of type Object and you'll need to convert it into MyThingy. Since it's a nullable (I'm assuming), you don't have to type cast but rather as-ify it.
MyThingy thingy = new MyThingy();
DataContractJsonSerializer serializer
= new DataContractJsonSerializer(thingy.GetType());
Stream stream = ...;
thingy = serializer.ReadObject(stream) as MyThingy;
You could of course skip the next-to-last line and put the stream directly into the last line.
Courtesy of #JohanLarsson (all Swedes are great, especially those from Stockholm, like me):
In case you can't or don't want to omit the StreamReader declaration in your using statement, I'd suggest that you take a look at BaseStream property to get to it.

You can try this:
using (StreamReader streamReader = new StreamReader(...))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(MyThingy));
MyThingy thingy = (MyThingy) serializer.ReadObject(streamReader.BaseStream);
}

I've been always using this:
// get stuff here
String json = GetJSON();
List<T> result;
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(typeof(List<T>));
result = (List<T>)serializer.ReadObject(ms);
}

Related

What should be done in order not to make an error while returning the json object or to be able to parse it properly?

I am an intern now. I'm just learning coding processes. I am returning a data as json object. My developer manager said that a query or operation should be done so that there is no problem when parsing the Json object. What action can be taken?
He said it should be done before the parcel process. I thought of the try catch method. But I don't think this is the definitive result. What kind of query or code should I write before the parse operation? Here I am returning the data in excel as json.
My code:
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(_appSetting.ExcelLicense);
byte[] excelData = System.IO.File.ReadAllBytes(fileName);
MemoryStream uploadExcelStream = new MemoryStream(excelData);
//Stream uploadExcelStream = data.File.OpenReadStream();
ExcelEngine excelEngine = new ExcelEngine();
IApplication application = excelEngine.Excel;
application.DefaultVersion = Path.GetExtension(fileName) == "xlsx" ? ExcelVersion.Xlsx : ExcelVersion.Excel97to2003;
IWorkbook book = application.Workbooks.Open(uploadExcelStream);
uploadExcelStream.Close();
MemoryStream jsonStream = new MemoryStream();
book.SaveAsJson(jsonStream, true);
excelEngine.Dispose();
byte[] json = new byte[jsonStream.Length];
jsonStream.Position = 0;
jsonStream.Read(json, 0, (int)jsonStream.Length);
string jsonString = Encoding.UTF8.GetString(json, 0, json.Length);
JObject jsonObject = JObject.Parse(jsonString);
var json2 = JsonConvert.SerializeObject(jsonObject);
return Json(json2, "application/json");
When converting from Excel to json, I was told that sometimes there may be a problem with the parse process and I need to write a query just above it. How can I do something so that there is no problem?
First up I think you could simplify the top part a little bit:
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
var jsonString = reader.ReadToEnd();
//OR
var jsonString = await reader.ReadToEndAsync(); //If you want to read async
As to your question, it´s a bit unclear what you are trying/supposed to do.
Since you are first desirializing your incoming json and then serialize it again to return, I can only assume you are supposed to do some kind of check on the object in between those two actions.

How to Trace and Process Stream with Json.Net

I am writing an application which will make a REST HTTP call and receive JSON back in the response body. The response body could be large and the content variable so I am wanting to handle it as a stream and process the content to decide which parts I want to deserialize.
I am able to perform my parsing and deserialize the objects I want using a StreamReader (passing in the HttpResponseMessage.Content, read as a stream) and a JsonTextReader. However, as the JsonTextReader pulls data from the stream, I would also like to trace the raw JSON to a file so that we have the raw response recorded (for diagnostics).
For example, my code:
var serializer = new JsonSerializer()
using (var streamReader = new StreamReader(httpContentStream))
using (var textReader = new JsonTextReader(streamReader))
{
textReader.SupportMultipleContent = true;
while (textReader.Read())
{
// Code which looks at the tokens in the text reader and
// figures out what to throw away, what to deserialize and
// what the next type to deserialize will be (stored in someType)
Type someType = null;
// Deserialize an object that we're interested in.
// This advances the textReader to the next token
// after then end of this object (I.E. More than one token)
var someObject = serializer .Deserialize(textReader, someType);
}
}
Is there a way to also have Json.Net trace out the string that its reading as it pulls characters off the stream? I understand that this could generate a large file!
Thanks in advance for any responses.

NewtonSoft Json Invalid Cast Exception

This is related to my question HTTPClient Buffer Exceeded 2G; Cannot write more bytes to the buffer but is different enough that IMO it warrants a separate question.
In the other question, I'm trying to figure out how to deal with breaking the 2G request buffer. The idea was to use streaming, but I need to deserialize. In talking to Professor Google, I found that I have to use TextReader to stream/deserialize. so my code for that is:
public async Task<API_Json_Special_Feeds.RootObject> walMart_Special_Feed_Lookup(string url)
{
special_Feed_Lookup_Working = true;
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
using (HttpClient http = new HttpClient(handler))
{
http.DefaultRequestHeaders.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip"));
http.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
url = String.Format(url);
using (var response = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
Console.WriteLine(response);
var serializer = new JsonSerializer();
using (StreamReader sr = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
using (var jsonTextReader = new JsonTextReader(sr))
{
API_Json_Special_Feeds.RootObject root = (API_Json_Special_Feeds.RootObject)serializer.Deserialize(jsonTextReader);
return root;
}
}
}
}
}
Now, as you can see, the return type is strongly typed. The return type of the method matches. Now, I go to the calling line:
API_Json_Special_Feeds.RootObject Items = await net.walMart_Special_Feed_Lookup(specialFeedsURLs[i].Replace("{apiKey}", Properties.Resources.API_Key_Walmart));
So, we have matching types API_Json_Special_Feeds.RootMethod all the way around.
When run, the calling line throws an InvalidCastException:
Undesired Result:
Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'RootObject'
I've checked at the end of the method before return, and the result is indeed cast from an object to API_Json_Special_Feeds.RootMethod before being returned.
Question: somewhere between the return statement and the calling line, the object being returned is being converted from an API_Json_Special_Feeds.RootMethod to a Newtonsoft.Json.Linq.JObject. I can't debug it since there's no code in between. If I cast again in the calling line, I get a "Cannot cast" error. How can I prevent the degradation/changing of this object type?
Many, many thinks for your time, consideration, and for any thoughts or suggestions you can provide!
You need to use the generic overload JsonSerializer.Deserialize<T>()
var root = serializer.Deserialize<API_Json_Special_Feeds.RootObject>(jsonTextReader);
Unlike files generated by BinaryFormatter, JSON files generally do not include c# type information, so it's necessary for the receiving system to specify the expected type.
(There are extensions to the JSON standard in which c# type information can be included in a JSON file -- e.g. Json.NET's TypeNameHandling -- but it is still necessary to deserialize the JSON to an appropriate explicit base class.)
See Deserialize JSON from a file for another example of deserializing a strongly typed c# object from a stream.

DataContractJsonSerializer: serialize object or array (can be both)

I'm accessing the tomtom json api, and the api either returns me an array of objects, or a single object, when an error has happen.
Example:
[{"driverno": "...
Error Example:
{"errorCode": "8011","errorMsg": "request quota reached, error code: 8011"}
The data is accessed WebRequest, WebResponse and they return a stream, which can then be passed to a DataContractJsonSerializer. However, I can't create a serialization class, which accepts both forms of JSON, and the stream can't be passed twice, because the seek function is not supported.
Is there a way, to create a serialization class which supports both types of JSON input?
I found a workaround, where I copy the Stream to a MemoryStream, which enables seeking. I'm not completly settisfied with th solution, becuase it does a Stream copying and the DataContractJsonSerializer twice.
Sample:
string text = File.ReadAllText(PAHT);
text = Regex.Replace(text, "\\{[\\n\\r ]*\"__type", "{\"__type");
// copy to MemoryStream
using (MemoryStream dataStream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
DataContractJsonSerializer errorDeserializer = new DataContractJsonSerializer(typeof(RequestError));
RequestError errorSerilaized = (RequestError)errorDeserializer.ReadObject(dataStream);
// check if an error happened
if (errorSerilaized.errorCode == null)
{
// seek the stream to position 0
dataStream.Position = 0;
DataContractJsonSerializer _deserializer = new DataContractJsonSerializer(typeof(NoneErrorSerializationClass));
NoneErrorSerializationClass tripReportsSerialized = (NoneErrorSerializationClass)_deserializer.ReadObject(dataStream);
// ...
}
else
{
MessageBox.Show(errorSerilaized.errorMsg);
}
}

How to write System.Xml.Linq.XElement using XmlWriter to a stream

I have an XElement instance and I wish to write to a stream using XmlWriter class. Why? Well, one of the configuration settings defines whether to use binary Xml or not. Based on this setting a suitable XmlWriter instance is created - either by XmlWriter.Create(stream) or XmlDictionaryWriter.CreateBinaryWriter(stream)).
Anyway, I am trying the following code, but it leaves the stream empty:
using (var stream = new MemoryStream())
{
var xmlReader = new XDocument(xml).CreateReader();
xmlReader.MoveToContent();
var xmlWriter = GetXmlWriter(stream);
xmlWriter.WriteNode(xmlReader, true);
return stream.ToArray();
}
I have checked, xmlReader is properly aligned after MoveToContent at the root XML element.
I must be doing something wrong, but what?
Thanks.
You haven't shown what GetXmlWriter does... but have you tried just flushing the writer?
xmlWriter.Flush();
Alternatively, wrap the XmlWriter in another using statement:
using (var stream = new MemoryStream())
{
var xmlReader = new XDocument(xml).CreateReader();
xmlReader.MoveToContent();
using (var xmlWriter = GetXmlWriter(stream))
{
xmlWriter.WriteNode(xmlReader, true);
}
return stream.ToArray();
}
You might want to do the same for the XmlReader as well, although in this particular case I don't believe you particularly need to.
Having said all this, I'm not entirely sure why you're using an XmlReader at all. Any reason you can't just find the relevant XElement and use XElement.WriteTo(XmlWriter)? Or if you're trying to copy the whole document, just use XDocument.WriteTo(XmlWriter)

Categories

Resources