Json.NET Disable the deserialization on DateTime - c#

Here is the code:
string s = "2012-08-08T01:54:45.3042880+00:00";
JObject j1 = JObject.FromObject(new
{
time=s
});
Object o = j1["time"];
We can check that o is string and equals "2012-08-08T01:54:45.3042880+00:00"
Now we transfer j1.ToString() to another program, which is
{
"time": "2012-08-08T01:54:45.3042880+00:00"
}
then at the other program, try to parse it back to JObject, which is
JObject j2 = JObject.Parse(j1.ToString());
Object o2 = j2["time"];
Now, if we check o2, o2's type is Date, o2.ToString() is 8/7/2012 9:54:45 PM.
My question is:
Is there is way to disable the Date deserialization for JObject.Parse , and just get the raw string?
Thanks in advance

When parsing from an object to JObject you can specify a JsonSerializer which instructs how to handle dates.
JObject.FromObject(new { time = s },
new JsonSerializer {
DateParseHandling = DateParseHandling.None
});
Unfortunately Parse doesn't have this option, although it would make sense to have it. Looking at the source for Parse we can see that all it does is instantiate a JsonReader and then passes that to Load. JsonReader does have parsing options.
You can achieve your desired result like this:
using(JsonReader reader = new JsonTextReader(new StringReader(j1.ToString()))) {
reader.DateParseHandling = DateParseHandling.None;
JObject o = JObject.Load(reader);
}
For background, see Json.NET interprets and modifies ISO dates when deserializing to JObject #862, specifically this comment from JamesNK: I have no plans to change it, and I would do it again if give the chance.

You can accomplish this using JsonConvert.DeserializeObject as well, by using JsonSerializerSettings:
string s = "2012-08-08T01:54:45.3042880+00:00";
string jsonStr = $#"{{""time"":""{s}""}}";
JObject j1 = JsonConvert.DeserializeObject<JObject>(jsonStr, new JsonSerializerSettings {DateParseHandling = DateParseHandling.None});

Related

Reading raw input inside JsonConverter.ReadJson [duplicate]

How can I efficiently get full json string in JsonConverter.ReadJson() ?
I can do:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
var json = JObject.Load(reader).ToString(Formatting.None);
However that seems very inefficient as I serialize and deserialize for no reason
Any better way ?
ReadJson() must fully parse the JSON being read so that the JSON is confirmed to be well-formed and the JsonReader is correctly positioned at the end of the current value upon exit. However, it is not necessary to load the entire JSON into an intermediate JObject hierarchy simply to re-convert it to a JSON string. Instead, you may be able to get better performance by using JRaw.Create():
var json = JRaw.Create(reader).ToString();
As can be seen in the reference source, this method streams directly from the incoming JsonReader to a StringWriter - without loading into an intermediate JToken hierarchy and re-serializing - by using JsonWriter.WriteToken(JsonReader):
public static JRaw Create(JsonReader reader)
{
using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
{
jsonWriter.WriteToken(reader);
return new JRaw(sw.ToString());
}
}
The resulting JRaw simply encapsulates that string in its Value. (Of course, there is no guarantee that the resulting JSON represents an object, only that it represents well-formed JSON.)
Note that JsonTextReader will automatically recognize and parse dates and times in common formats as DateTime objects, and also parse floating point values as double. If you need the "most literal" JSON string you may want to suppress DateTime recognition and/or parse floating point values as decimal. The following extension method, modeled on JRaw.Create(), does the job:
public static string ReadOuterJson(this JsonReader reader, Formatting formatting = Formatting.None, DateParseHandling? dateParseHandling = null, FloatParseHandling? floatParseHandling = null)
{
// If you would prefer a null JSON value to return an empty string, remove this line:
if (reader.TokenType == JsonToken.Null)
return null;
var oldDateParseHandling = reader.DateParseHandling;
var oldFloatParseHandling = reader.FloatParseHandling;
try
{
if (dateParseHandling != null)
reader.DateParseHandling = dateParseHandling.Value;
if (floatParseHandling != null)
reader.FloatParseHandling = floatParseHandling.Value;
using (var sw = new StringWriter(CultureInfo.InvariantCulture))
using (var jsonWriter = new JsonTextWriter(sw) { Formatting = formatting })
{
jsonWriter.WriteToken(reader);
return sw.ToString();
}
}
finally
{
reader.DateParseHandling = oldDateParseHandling;
reader.FloatParseHandling = oldFloatParseHandling;
}
}
And then call it like, e.g.:
var json = reader.ReadOuterJson(dateParseHandling: DateParseHandling.None);
For details on why this may be necessary, see:
Json.NET interprets and modifies ISO dates when deserializing to JObject #862.
JObject.Parse modifies end of floating point values.

How to construct object programmatically inside of JsonConverter WriteObject

I am trying to create structure of nested objects on the flight inside of JsonConverter.WriteObject function.
Data structure:
Container
Object A
Object B
What am I doing wrong?
Can anyone recommend decent guide for writing Custom Converters?
var container = new JObject();
var fi = e.PropertyA;
JObject o = JObject.FromObject(fi);
o.AddFirst(new JProperty("type", new JValue(fi.GetType().Name)));
container.Add(o);
this approach failed with exception
Can not add Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JObject
if I do
writer.WriteStartObject();
var fi = e.PropertyA;
JObject o = JObject.FromObject(fi);
o.AddFirst(new JProperty("type", new JValue(fi.GetType().Name)));
o.WriteTo(writer);
writer.WriteEndObject();
'Token StartObject in state ObjectStart would result in an invalid JSON object. Path 'sources[0]'.'
Answer
Thanks to dbc I was able to make it trough with following code
var container = new JObject();
var fi = e.PropertyA;
JObject o = JObject.FromObject(fi);
o.AddFirst(new JProperty("type", new JValue(fi.GetType().Name)));
container.Add(new JProperty("ObjectA", o));
container.WriteTo(writer);
According to the JSON standard a JSON object is an unordered set of name/value pairs so when writing an object you need to do WritePropertyName() before writing a property value:
writer.WritePropertyName("PropertyA");
o.WriteTo(writer);
Similarly when adding a JObject to a JObject you need to nest it in a JProperty to specify the name:
container.Add(new JProperty("PropertyA", o));
The exceptions you are getting reflect the fact that you are trying to add your PropertyA value to a JSON object without first specifying its name.
Working .Net fiddle showing both.

How to deserialize JSON (snake_case) to dynamic (PascalCase)?

This code works fine:
string json = #"{""MyProperty"" : ""bar""}";
var payload = JsonConvert.DeserializeObject<dynamic>(json);
string typedProperty = payload.MyProperty; //contains "bar"
Let's try to do the same with snake_case JSON. We add a SnakeCaseNamingStrategy which is actually a recommended way to handle snake_case.
_snakeSettings = new JsonSerializerSettings()
{
ContractResolver = new UnderscorePropertyNamesContractResolver()
};
public class UnderscorePropertyNamesContractResolver : DefaultContractResolver
{
public UnderscorePropertyNamesContractResolver()
{
NamingStrategy = new SnakeCaseNamingStrategy();
}
}
Then, apply the settings to the DeserializeObject call. In case of deserialization to a static type, those settings are successfully applied to snake_case JSON:
string snakeJson = #"{""my_property"" : ""bar""}";
var payload = JsonConvert.DeserializeObject<Payload>(snakeJson, _snakeSettings);
string typedProperty = payload.MyProperty; //contains "bar"
OK, switch the target type to dynamic:
var payload = JsonConvert.DeserializeObject<dynamic>(snakeJson, _snakeSettings);
string typedProperty = payload.MyProperty; //is null
string wrongProperty = payload.my_property; //is not null
As you see, _snakeSettings are ignored this time. I guess this is a bug. Does any workaround exist to do JSON (snake_case) -> dynamic (PascalCase) deserialization?
Environment:
<TargetFramework>netcoreapp1.1</TargetFramework>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
When you call JsonConvert.DeserializeObject<dynamic> it acts the same way as JsonConvert.DeserializeObject<JObject>. JObject is not a real result of the deserialization, but some intermediate state of your data, It is closer to readers than to objects. E.g. it allows you to deserialize only part of a JSON
So seems like JsonConvert.DeserializeObject<dynamic> creates not a result object but a reach, functional reader for the JSON data. I suppose, that's why it shows you data as it was without any post processing
I suppose it's better to direct that question to a "Newtonsoft.Json" developers.

String date property of object is deserialized to another format even though it should remain unchanged [duplicate]

Here is the code:
string s = "2012-08-08T01:54:45.3042880+00:00";
JObject j1 = JObject.FromObject(new
{
time=s
});
Object o = j1["time"];
We can check that o is string and equals "2012-08-08T01:54:45.3042880+00:00"
Now we transfer j1.ToString() to another program, which is
{
"time": "2012-08-08T01:54:45.3042880+00:00"
}
then at the other program, try to parse it back to JObject, which is
JObject j2 = JObject.Parse(j1.ToString());
Object o2 = j2["time"];
Now, if we check o2, o2's type is Date, o2.ToString() is 8/7/2012 9:54:45 PM.
My question is:
Is there is way to disable the Date deserialization for JObject.Parse , and just get the raw string?
Thanks in advance
When parsing from an object to JObject you can specify a JsonSerializer which instructs how to handle dates.
JObject.FromObject(new { time = s },
new JsonSerializer {
DateParseHandling = DateParseHandling.None
});
Unfortunately Parse doesn't have this option, although it would make sense to have it. Looking at the source for Parse we can see that all it does is instantiate a JsonReader and then passes that to Load. JsonReader does have parsing options.
You can achieve your desired result like this:
using(JsonReader reader = new JsonTextReader(new StringReader(j1.ToString()))) {
reader.DateParseHandling = DateParseHandling.None;
JObject o = JObject.Load(reader);
}
For background, see Json.NET interprets and modifies ISO dates when deserializing to JObject #862, specifically this comment from JamesNK: I have no plans to change it, and I would do it again if give the chance.
You can accomplish this using JsonConvert.DeserializeObject as well, by using JsonSerializerSettings:
string s = "2012-08-08T01:54:45.3042880+00:00";
string jsonStr = $#"{{""time"":""{s}""}}";
JObject j1 = JsonConvert.DeserializeObject<JObject>(jsonStr, new JsonSerializerSettings {DateParseHandling = DateParseHandling.None});

How to deserialize JSON object with json.net

StreamReader qryTmpltStream = new StreamReader(tmpltPath + "templates.json");
JsonTextReader qryTmpltReader = new JsonTextReader(qryTmpltStream);
JsonSerializer qryTmpltSrlzr = new JsonSerializer();
object jsonObject = qryTmpltSrlzr.Deserialize(qryTmpltReader);
var tplts = JsonConvert.DeserializeObject<JSONRepClass>(jsonObject);
In above code I'm trying to read in a json file then deserialize it into a class. The problem is, this: JsonConvert.DeserializeObject wants a string, but the Deserailize method call before it returns an object.
I tried casting to string and ToString(), but no go.
Anyone see what I'm missing here?
Try this, just read the json file contents into a string and deserialize it using Json.Net
var jSonString = File.ReadAllText(tmpltPath + "templates.json");
var tplts = JsonConvert.DeserializeObject<JSONRepClass>(jsonString);
This is the simplest way to use JSON.net to turn a json string into a strongly typed class.
YourClass myclass = new YourClass();
JsonConvert.PopulateObject(yourstring,myclass);

Categories