C# Newtonsoft JsonConvert can't deserializeDateTime properly - c#

We have a MVC.Core project where we're having problems deserializing a DateTime value from a string into a DateTime property.
Here's an example:
public class TestClass
{
public RecordStatus RecordStatus { get; set; } = RecordStatus.Active;
[System.ComponentModel.Browsable(false)]
public DateTime CreatedOn { get; private set; }
}
string s = #"{""recordStatus"":""Active"",""createdOn"":""2018-03-02T21:39:22.075Z""}";
JsonSerializerSettings jsonSettings = new JsonSerializerSettings()
{
DateFormatString = "yyyy-MM-ddTHH:mm:ss.FFFZ",
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
MissingMemberHandling = MissingMemberHandling.Ignore
};
TestClass psm = JsonConvert.DeserializeObject<TestClass>(s, jsonSettings);
The value of psm.CreatedOn is being set to
{1/1/0001 12:00:00 AM}
I've tried a bunch of different combination of values for the serializer settings with no luck. What am I missing here? I know I'm missing something obvious, but it's on of those days.
Thanks

The problem here isn't the format string, that is just fine (as we can see here):
Console.WriteLine(DateTime.ParseExact("2018-03-02T21:39:22.075Z","yyyy-MM-ddTHH:mm:ss.FFFZ", CultureInfo.InvariantCulture));
Yields:
02-Mar-18 4:39:22 PM
The issue is actually the private setter on CreatedOn. If you remove that everything works. In fact, it works with the default serializer settings, so there is no need to do anything with that format string.
If you are set on having a private setter for that field, then I would suggest looking into something like this to make Json.NET use the private setter.

public class TestClass
{
public RecordStatus RecordStatus { get; set; } = RecordStatus.Active;
[System.ComponentModel.Browsable(false)]
public DateTime CreatedOn { get; set; }
}
Remove the private access modifier from the setter for the CreatedOn property

Related

IsoDateTimeConverter and JsonSerializerSettings: differentiate DateTime with DateTimeOffset

In my C# models I use both DateTime and DateTimeOffset, eg:
class Foo
{
public DateTime Date { get; set; }
public DateTimeOffset CreationDate { get; set; }
}
When I serialize to JSON, I do it like this:
Foo foo = new Foo();
foo.Date = DateTime.UtcNow;
foo.CreationDate = DateTime.UtcNow;
var isoDateTimeConverter = new IsoDateTimeConverter();
isoDateTimeConverter.DateTimeFormat = "yyyy'-'MM'-'dd";
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(isoDateTimeConverter);
JsonSerializer serializer = JsonSerializer.Create(serializerSettings);
serializer.Serialize(writer, foo);
This will produce this JSON:
{
Date = "2019-02-26",
CreationDate = "2019-02-26"
}
Both Date and CreationDate are serialized the same way due to IsoDateTimeConverter
What I'd like to do is to differentiate the serialization of DateTime and DateTimeOffset
My goal is to get this JSON:
{
Date = "2019-02-26",
CreationDate = "2019-02-26T12:03:00-03:00"
}
How can I achieve this?
Additional info:
When my C# model uses DateTime, I save it as Date in SQL Server
When my C# model uses DateTimeOffset, I save it as DateTimeOffset in SQL Server
I'm using EF Code First
You can try this
public class DateFormatConverter : IsoDateTimeConverter
{
public DateFormatConverter(string format)
{
DateTimeFormat = format;
}
}
Specify the format for each Date properties
public class Foo
{
[JsonConverter(typeof(DateFormatConverter), "yyyy-MM-dd")]
public DateTime Date { get; set; }
[JsonConverter(typeof(DateFormatConverter), "yyyy-MM-ddTHH:mm:ssK")]
public DateTimeOffset CreationDate { get; set; }
}
Without additional settings, you can Serialize
Foo foo = new Foo();
foo.Date = DateTime.UtcNow;
foo.CreationDate = DateTime.UtcNow;
string isoJson = JsonConvert.SerializeObject(foo);
OUTPUT
{"Date":"2020-02-26","CreationDate":"2020-02-26T15:30:19-03:00"}

JSON change value

I have a JSON value like this
{"$id":"649271776","$type":"outdoorgame","Overs":50,"Balls":6,"TeamName":"TestTeam"}
I wrote a C# code like this to change the value of Overs from 50 to 10
var jsonString = sSession.GameState; //this is the value {"$id":"649271776","$type":"outdoorgame","Overs":50,"Balls":6,"TeamName":"TestTeam"}
dynamic jsonObject =
Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
jsonObject.Overs = 10;
var modifiedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject);
This code is changing the value of Overs from 50 to 10. The problem I am facing when I use the above code modifiedJsonString is missing these two values
"$id":"649271776","$type":"outdoorgame"
giving the output as {Overs":10,"Balls":6,"TeamName":"TestTeam"} I want $id and $type also in the modifiedJsonString.
I want modifiedJsonString like this {"$id":"649271776","$type":"outdoorgame","Overs":10,"Balls":6,"TeamName":"TestTeam"}
Can anyone tell me how to solve this problem
The problem is that $id and $type are not valid identifiers, and can't appear as members of the returned dynamic object built by the JSON serializer. As in gldraphael's answer, the solution is to create your own concrete class to hold the deserialized object; for the properties whose names start with $ you'll need to use JsonPropertyAttribute to remap the names:
public class GameState
{
[JsonProperty("$id")] public string ID { get; set; }
[JsonProperty("$type")] public string Type { get; set; }
int Overs { get; set; }
int Balls { get; set; }
public string TeamName { get; set; }
}
Further, Json.NET treats $type as a special property name and this interferes with proper deserialization of your object. To get around this, we must use the MetadataPropertyHandling.Ignore serializer setting.
Thus you can deserialize, modify and re-serialize like this:
string jsonString = "{\"$id\":\"649271776\",\"$type\":\"outdoorgame\",\"Overs\":50,\"Balls\":6,\"TeamName\":\"TestTeam\"}";
JsonSerializerSettings settings = new JsonSerializerSettings() { MetadataPropertyHandling = MetadataPropertyHandling.Ignore };
GameState jsonObject = JsonConvert.DeserializeObject<GameState>(jsonString, settings);
jsonObject.Overs = 10;
var modifiedJsonString = JsonConvert.SerializeObject(jsonObject);
See it in action.
You can use JToken to handle this.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
var jsonString = "{\"$id\":\"649271776\",\"$type\":\"outdoorgame\",\"Overs\":50,\"Balls\":6,\"TeamName\":\"TestTeam\"}";
JToken jsonObject = JToken.Parse(jsonString);
jsonObject["Overs"] = 10;
var modifiedJsonString = JsonConvert.SerializeObject(jsonObject);
// In case one wanted to update the $type and $id fields
jsonObject["$type"] = "asdf";
jsonObject["$id"] = 123456;
var modifiedJsonString2 = JsonConvert.SerializeObject(jsonObject);
Will result in:
modifiedJsonString --> {"$id":"649271776","$type":"outdoorgame","Overs":10,"Balls":6,"TeamName":"TestTeam"}
And if you needed to update $id and $type, that is possible, too.
modifiedJsonString2 -->
{"$id":123456,"$type":"asdf","Overs":10,"Balls":6,"TeamName":"TestTeam"}
Demo on .NET Fiddle: https://dotnetfiddle.net/a370Mv
Use a concrete class. You'll need to annotate the fields with $ prefixes manually. Eg:
public class Example
{
public string Field { get; set; }
[JsonProperty("$type")]
public string Type { get; set; }
}
Here's a working example.
In your case the class will look something like:
public class ObjName
{
[JsonProperty("$id")]
public string Id { get; set; }
[JsonProperty("$type")]
public string Type { get; set; }
public int Overs { get; set; }
public int Balls { get; set; }
public string TeamName { get; set; }
}
(Just be mindful of the property case).

How to deserialize object with date in C# [duplicate]

This question already has answers here:
Deserializing dates with dd/MM/yyyy format using Json.Net
(9 answers)
Closed 6 years ago.
I have this Json from a web api:
jsonstring ={"users":[{"id":1123,"last_update":"2016-02-28 14:53:04"}],"page":1,"pages":1}
which I want to deserialize in an object like:
public class Rootobject
{
public User[] users { get; set; }
public int page { get; set; }
public int pages { get; set; }
}
public class User
{
public int id { get; set; }
public DateTime last_update { get; set; }
}
for this I use:
var obj= JsonConvert.DeserializeObject<Rootobject>(jsonString);
the result has null for last_update.
jsonstring is a string result from WebClient.DownloadString(url); which look like above example.
How can I get the date on deserialization?
Edit:
None of the solutions from this post Deserializing dates with dd/mm/yyyy format using Json.Net help me fix my issue.
var obj = JsonConvert.DeserializeObject<Rootobject>(jsonString,
new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
Fiddle
Change the property last_update as Nullable, Then it allows you to assign the null literal to the DateTime type. It provides another level of indirection. So use like the following:
public DateTime? last_update { get; set; }
This is for accepting The date even if it is null, you can specify the Date format While Deserializing the JSON. Use this Thread for that
"2016-02-28 14:53:04" is not a valid RFC3339 date time, and I think it can't parse it because of that.
It has to be:
2016-02-28T14:53:04
Also note that the can't be null, since DateTime is a struct. To make it nullable, make the data type DateTime? which does allow null values.

ServiceStack.Text and ISODate("")

Why ServiceStack.Text DeserializeFromString cant convert ISODate formats.
For example, i have json string like
{ "Count" : 4, "Type" : 1, "Date" : ISODate("2013-04-12T00:00:00Z") }
and class
public class TestClass
{
public int Count { get; set; }
public int Type { get; set; }
public DateTime Date { get; set; }
}
and when i try to deserialize from string
JsonSerializer.DeserializeFromString<TestClass>(json);
give me output like
ServiceStack.Text understands ISO8601, too.
You can configure it as the default behaviour with:
JsConfig.DateHandler = JsonDateHandler.ISO8601;
See this answer for more information.
JSON expects the date format like this
"LastRequestTime":"\/Date(928129800000+0530)\/"
So change you date value in Json string and then try. it will deserialized that property properly.

Why when I deserialize with JSON.NET ignores my default value?

I'm using JSON.NET as my main serializer.
This is my model, look that I've setted some JSONProperties and a DefaultValue.
public class AssignmentContentItem
{
[JsonProperty("Id")]
public string Id { get; set; }
[JsonProperty("Qty")]
[DefaultValue(1)]
public int Quantity { get; set; }
}
When I serialize a List<AssignmentContentItem>, it doing a good work:
private static JsonSerializerSettings s = new JsonSerializerSettings
{
DefaultValueHandling = DefaultValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};
OUTPUT:
[{"Id":"Q0"},{"Id":"Q4"},{"Id":"Q7"}]
But when I'd like to deserialize this jsonContent, the property Qty is always 0 and is not set to the default value. I mean, when I deserialize that jsonContent, as DefaultValue for Quantity should be one instead of 0.
public static List<AssignmentContentItem> DeserializeAssignmentContent(string jsonContent)
{
return JsonConvert.DeserializeObject<List<AssignmentContentItem>>(jsonContent, s);
}
What should I do
The DefaultValue attribute does not set the value of the property. See this question: .NET DefaultValue attribute
What you might be better off doing is setting the value in the constructor:
public class AssignmentContentItem
{
[JsonProperty("Id")]
public string Id { get; set; }
[JsonProperty("Qty")]
public int Quantity { get; set; }
public AssignmentContentItem()
{
this.Quantity = 1;
}
}
Where this line:
AssignmentContentItem item =
JsonConvert.DeserializeObject<AssignmentContentItem>("{\"Id\":\"Q0\"}");
Results in an AssignmentContentItem with its Quantity set to 1.
You can use the the DefaultValueHandling.Populate setting so that Json.Net will populate the created object with the default value.
public static List<AssignmentContentItem> DeserializeAssignmentContent(string jsonContent)
{
return JsonConvert.DeserializeObject<List<AssignmentContentItem>>(jsonContent, new JsonSerializerSettings
{
DefaultValueHandling = DefaultValueHandling.Populate,
NullValueHandling = NullValueHandling.Ignore
});
}
http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_DefaultValueHandling.htm

Categories

Resources