Read as much JSON data from the stream as possible - c#

Is there any way to read a JSON object from the stream where it's followed by other data, and thus the only way to find out that we should stop reading is by reaching the position where the object's opening brace is closed?
{
"SomeData": "blahblah",
"SubObject": {
"SomeData": "blahblah}{{"
}
}
... and some more text (not JSON)

I assume you're going to use Json.Net library. In this case it will cater for your particular use case out of the box.
consider the following:
var s = "{ \"SomeData\": \"blahblah\", \"SubObject\": {\"SomeData\": \"blahblah}{{\" } } sdfsdfsdf... and some more data";
var obj1 = JsonConvert.DeserializeObject(s, new JsonSerializerSettings() {
CheckAdditionalContent = false // this is the key here, otherwise you will get an exception
});
JsonSerializer serializer = new JsonSerializer();
var obj2 = serializer.Deserialize(new JsonTextReader(new StringReader(s))); // no issues here either

Related

How to write a string property value to JsonTextWriter with a TextWriter?

I have C# class that can have content of various types, and an method that can write that content to a TextWriter in an efficient manner. In certain cases, I have a collection of these objects that I write out as JSON array. So, I have a JsonTextWriter which is set up appropriately. It's in a state where I have called the methods to create the container JObject, JArray and JObject. I've called JsonTextWriter.WritePropertyName() and now comes this instance method.
public void WriteContentToValue(JsonTextWriter writer)
{
if (this.Content is JToken) {
(this.Content as JToken).WriteTo(writer);
} else {
using (StringWriter swriter = new StringWriter()) {
WriteContentTo(swriter);
writer.WriteValue(swriter.ToString());
}
}
}
WriteContentTo(swriter) is a call to the method I mentioned earlier that takes a TextWriter. I'm looking for a alternative to the code in the else block that doesn't involve creating a StringWriter instance and forcing creation of an intermediary string with StringWriter.ToString() in order to call JsonTextWriter.WriteValue(string).
There is no deserialization happening in this that I can see.
JObject o = new JObject(
new JProperty("Name", "John Smith"),
new JProperty("BirthDate", new DateTime(1983, 3, 20))
);
JsonSerializer serializer = new JsonSerializer();
Person p = (Person)serializer.Deserialize(new JTokenReader(o), typeof(Person));
Console.WriteLine(p.Name);
When using StringWriter be sure to be careful of your instances.
I would highly recommend looking into the documentation on this as well. https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenWriter.htm

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());

Discarding garbage characters after json object with Json.Net

I have to consume a so called web service implemented by a dumb monkey which is returning some garbage after the proper Json response.
Something like this:
{
"Property1": 1,
"Property2": 2,
"Property3": 3
}<?xml version='1.0' ?>Maybe some other gibberish nonsense I wish to discard.
Now, I could just search for "<?xml" and split, but I was wondering if I can use a stream reader or something to read up to the closing } and then discard the rest.
I'm using C# and Json.Net.
You can also set JsonSerializerSettings.CheckAdditionalContent = false to tell the serializer to ignore any content after the end of the deserialized JSON object:
var result = JsonConvert.DeserializeObject<Dictionary<string, long>>(json, new JsonSerializerSettings { CheckAdditionalContent = false })
Oddly enough it is necessary to do this explicitly despite the fact that the default value seems to be false already, since the underlying field is nullable.
I knew there had to be a simple and robust way:
public T ReadTypeAndDiscardTheRest<T>(string json)
{
using (var sr = new StringReader(json))
using (var jsonReader = new JsonTextReader(sr))
{
var token = JToken.Load(jsonReader);
return token.ToObject<T>();
}
}
[Test]
public void TestJsonDiscarding()
{
var json = #"{""Key"":""a"", ""Value"":""n""}<?xml>aaaa";
var kp = ReadTypeAndDiscardTheRest<KeyValuePair<string, string>>(json);
Assert.That(kp.Key, Is.EqualTo("a"));
Assert.That(kp.Value, Is.EqualTo("n"));
}
As always, Json.Net FTW.

Invalid Operation Exception , No elements in the sequence

private static void WriteJson(string filepath,
string filename,
JsonSchema jsonschema)
{
using (TextWriter writer = File.CreateText(
#"C:\Users\ashutosh\Desktop\Output\" + filename + ".js"))
using (var jtw = new JsonTextWriter(writer))
{
jtw.Formatting = Formatting.Indented;
jsonschema.WriteTo(jtw);
}
//var json = JsonConvert.SerializeObject(
// jsonschema, Formatting.Indented,
// new JsonSerializerSettings {
// NullValueHandling = NullValueHandling.Ignore });
// File.WriteAllText(
// #"C:\Users\ashutosh\Desktop\Output\" + filename + ".js", json);
}
I am creating a JSONSchema from JSON.net , and then writing it out . I get a
Invalid Operation Exception Sequence contains no matching element
But when I use the commented code instead of the usual stuff. No such exception appears.
1) What is causing this exception?
2) I would have used the second method happily but it doesn't feel intuitive and it will print out the integer value of the JsonType for schema.Type instead of the (array,integer,bool etc..)
What can I do to get out of this situation?
UPDATE
The exception happens when the "Properties" property of the JsonSchema has count = 0 .
Properties is Dictionary<String,JsonSchema>. I have initialise it so it is not null. Eventually the code may or may not add elements to it . so , the count may remain 0.
By default, enums will be serialized to theirs corresponding integer value. You can change that easily by supplying StringEnumConverter in your serializer settings:
var json = JsonConvert.SerializeObject(jsonschema, Formatting.Indented,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
Converters = new List<JsonConverter> { new StringEnumConverter() }
});
Edit:
I run this simple test code:
var schema = new JsonSchemaGenerator().Generate(typeof(CustomType));
Debug.Assert(schema.Properties.Count == 0);
using (TextWriter textWriter = File.CreateText(#"schema.json"))
using (var jsonTextWriter = new JsonTextWriter(textWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
schema.WriteTo(jsonTextWriter);
}
// CustomType is a class without any fields/properties
public class CustomType { }
Code above serializes schema correctly to:
{
"type": "object",
"properties": {}
}
Is the schema you are generating correct? It seems as if serializer was "thinking" it should deal with some properties when there are actually none. Can you show type you generate schema from? There might be a problem with type which causes invalid schema to generate - but still, I cannot reproduce it.

How do I serialize a C# anonymous type to a JSON string?

I'm attempting to use the following code to serialize an anonymous type to JSON:
var serializer = new DataContractJsonSerializer(thing.GetType());
var ms = new MemoryStream();
serializer.WriteObject(ms, thing);
var json = Encoding.Default.GetString(ms.ToArray());
However, I get the following exception when this is executed:
Type
'<>f__AnonymousType1`3[System.Int32,System.Int32,System.Object[]]'
cannot be serialized. Consider marking
it with the DataContractAttribute
attribute, and marking all of its
members you want serialized with the
DataMemberAttribute attribute. See
the Microsoft .NET Framework
documentation for other supported
types.
I can't apply attributes to an anonymous type (as far as I know). Is there another way to do this serialization or am I missing something?
Try the JavaScriptSerializer instead of the DataContractJsonSerializer
JavaScriptSerializer serializer = new JavaScriptSerializer();
var output = serializer.Serialize(your_anon_object);
As others have mentioned, Newtonsoft JSON.NET is a good option. Here is a specific example for simple JSON serialization:
return JsonConvert.SerializeObject(
new
{
DataElement1,
SomethingElse
});
I have found it to be a very flexible, versatile library.
You can try my ServiceStack JsonSerializer it's the fastest .NET JSON serializer at the moment. It supports serializing DataContract's, Any POCO Type, Interfaces, Late-bound objects including anonymous types, etc.
Basic Example
var customer = new Customer { Name="Joe Bloggs", Age=31 };
var json = customer.ToJson();
var fromJson = json.FromJson<Customer>();
Note: Only use Microsofts JavaScriptSerializer if performance is not important to you as I've had to leave it out of my benchmarks since its up to 40x-100x slower than the other JSON serializers.
For those checking this around the year 2020:
Microsoft's System.Text.Json namespace is the new king in town. In terms of performance, it is the best as far as I can tell:
var model = new Model
{
Name = "Test Name",
Age = 5
};
string json = JsonSerializer.Serialize(model);
As some others have mentioned, NewtonSoft.Json is a very nice library as well.
The fastest way I found was this:
var obj = new {Id = thing.Id, Name = thing.Name, Age = 30};
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(obj);
Namespace: System.Web.Script.Serialization.JavaScriptSerializer
Please note this is from 2008. Today I would argue that the serializer should be built in and that you can probably use swagger + attributes to inform consumers about your endpoint and return data.
Iwould argue that you shouldn't be serializing an anonymous type. I know the temptation here; you want to quickly generate some throw-away types that are just going to be used in a loosely type environment aka Javascript in the browser. Still, I would create an actual type and decorate it as Serializable. Then you can strongly type your web methods. While this doesn't matter one iota for Javascript, it does add some self-documentation to the method. Any reasonably experienced programmer will be able to look at the function signature and say, "Oh, this is type Foo! I know how that should look in JSON."
Having said that, you might try JSON.Net to do the serialization. I have no idea if it will work
You could use Newtonsoft.Json.
var warningJSON = JsonConvert.SerializeObject(new {
warningMessage = "You have been warned..."
});
A faster alternative with Microsofts' new library on System.Text.Json
var warningJSON = JsonSerializer.Serialize(new {
warningMessage = "You have been warned..."
});
Assuming you are using this for a web service, you can just apply the following attribute to the class:
[System.Web.Script.Services.ScriptService]
Then the following attribute to each method that should return Json:
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
And set the return type for the methods to be "object"
public static class JsonSerializer
{
public static string Serialize<T>(this T data)
{
try
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
var stream = new MemoryStream();
serializer.WriteObject(stream, data);
string jsonData = Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
stream.Close();
return jsonData;
}
catch
{
return "";
}
}
public static T Deserialize<T>(this string jsonData)
{
try
{
DataContractJsonSerializer slzr = new DataContractJsonSerializer(typeof(T));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonData));
T data = (T)slzr.ReadObject(stream);
stream.Close();
return data;
}
catch
{
return default(T);
}
}
}

Categories