Answered by:
UTC Date is being deserialized to server local time when PUT and PATCH.

Question
-
User1649945628 posted
When I sending data in a HTTP Request with POST method, any date string formatted like "2016-02-05T15:00:00.000Z" is deserialized correctly as UTC date time at the server side. But with PUT or PATCH method, it will deserialize it as local date time. It extremely annoying when I using ODATA v4 $Patch method sending POST/PUT/PATCH in a same batch and need to twist the date time in order to workaround the bug.
I noticed that someone had complain about the GET method long ago.
Can someone comment on the issue?
Thanks in advance!
Richard.
Friday, February 5, 2016 8:10 PM
Answers
-
User36583972 posted
Hi rtang2011,
From your description, I suggest you can customize CustomJsonMediaTypeFormatter class. Through this you can correctly handle type, to ensure data consistency before and after.
The following code for your reference.
CustomJsonMediaTypeFormatter:
public class CustomJsonMediaTypeFormatter : MediaTypeFormatter { public JsonSerializerSettings _jsonSerializerSettings; public CustomJsonMediaTypeFormatter() { _jsonSerializerSettings = CustomJsonSettings.Instance; // Fill out the mediatype and encoding we support SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); SupportedEncodings.Add(new UTF8Encoding(false, true)); } public override bool CanReadType(Type type) { return true; } public override bool CanWriteType(Type type) { return true; } public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger) { // Create a serializer Newtonsoft.Json.JsonSerializer serializer = Newtonsoft.Json.JsonSerializer.Create(_jsonSerializerSettings); // Create task reading the content return Task.Factory.StartNew(() => { using (StreamReader streamReader = new StreamReader(stream, SupportedEncodings.First())) { using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader)) { return serializer.Deserialize(jsonTextReader, type); } } }); } public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext) { // Create a serializer Newtonsoft.Json.JsonSerializer serializer = Newtonsoft.Json.JsonSerializer.Create(_jsonSerializerSettings); // Create task writing the serialized content return Task.Factory.StartNew(() => { using (StreamWriter streamWriter = new StreamWriter(stream, SupportedEncodings.First())) { using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter)) { serializer.Serialize(jsonTextWriter, value); } } }); } } public static class CustomJsonSettings { private static JsonSerializerSettings _settings; public static JsonSerializerSettings Instance { get { if (_settings == null) { var settings = new JsonSerializerSettings(); // Must convert times coming from the client (always in UTC) to local - need both these parts: JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); settings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = System.Globalization.DateTimeStyles.AssumeUniversal }); // Critical part 1 settings.DateTimeZoneHandling = DateTimeZoneHandling.Local; // Critical part 2 // Skip circular references settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // Handle special cases in json (self-referencing loops, etc) //settings.ContractResolver = new CustomJsonResolver(); _settings = settings; } return _settings; } } }
WebApiConfig:
public static void Register(HttpConfiguration config) { GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter); GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); GlobalConfiguration.Configuration.Formatters.Add(new CustomJsonMediaTypeFormatter()); ODataModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Category>("Category"); config.MapODataServiceRoute( routeName: "ODataRoute", routePrefix: "odata", model: builder.GetEdmModel()); }
The tutorial about Using JSON.NET with ASP.NET Web API in the below:
https://code.msdn.microsoft.com/Using-JSONNET-with-ASPNET-b2423706
Best Regards,
Yohann Lu
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Tuesday, February 23, 2016 6:45 AM
All replies
-
User1814019480 posted
hi rtang,
I wonder know how do you parse your date string on server side?
I guess you may need use the DateTimeOffset method or SpecifyKind method. The similar thread about this issue , please refer to it:
Regards,
Will
Tuesday, February 9, 2016 10:49 AM -
User1649945628 posted
Hi will,
I'm sending the data in JSON format. From the server side I'm not doing any manual de-serialization. It's very hard for me to change all DateTime properties to DateTimeOffset at this stage. The controllers are derived from ODataController. When I sending the same Date Time data to POST or PUT, it's de-serialized with different value. For example, the following two methods get different Date information even when the same data were sent:
[System.Web.Http.HttpPost]
public IHttpActionResult Post([FromBody] Category category)
{
//category.UpdateDate is correct;
}[System.Web.Http.HttpPut]
public IHttpActionResult Put([FromODataUri] int id, [FromBody] Category category)
{
//category.UpdateDate is incorrect;
}Wednesday, February 10, 2016 9:01 PM -
User36583972 posted
Hi rtang2011,
From your description, I suggest you can customize CustomJsonMediaTypeFormatter class. Through this you can correctly handle type, to ensure data consistency before and after.
The following code for your reference.
CustomJsonMediaTypeFormatter:
public class CustomJsonMediaTypeFormatter : MediaTypeFormatter { public JsonSerializerSettings _jsonSerializerSettings; public CustomJsonMediaTypeFormatter() { _jsonSerializerSettings = CustomJsonSettings.Instance; // Fill out the mediatype and encoding we support SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); SupportedEncodings.Add(new UTF8Encoding(false, true)); } public override bool CanReadType(Type type) { return true; } public override bool CanWriteType(Type type) { return true; } public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger) { // Create a serializer Newtonsoft.Json.JsonSerializer serializer = Newtonsoft.Json.JsonSerializer.Create(_jsonSerializerSettings); // Create task reading the content return Task.Factory.StartNew(() => { using (StreamReader streamReader = new StreamReader(stream, SupportedEncodings.First())) { using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader)) { return serializer.Deserialize(jsonTextReader, type); } } }); } public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext) { // Create a serializer Newtonsoft.Json.JsonSerializer serializer = Newtonsoft.Json.JsonSerializer.Create(_jsonSerializerSettings); // Create task writing the serialized content return Task.Factory.StartNew(() => { using (StreamWriter streamWriter = new StreamWriter(stream, SupportedEncodings.First())) { using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter)) { serializer.Serialize(jsonTextWriter, value); } } }); } } public static class CustomJsonSettings { private static JsonSerializerSettings _settings; public static JsonSerializerSettings Instance { get { if (_settings == null) { var settings = new JsonSerializerSettings(); // Must convert times coming from the client (always in UTC) to local - need both these parts: JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); settings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = System.Globalization.DateTimeStyles.AssumeUniversal }); // Critical part 1 settings.DateTimeZoneHandling = DateTimeZoneHandling.Local; // Critical part 2 // Skip circular references settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // Handle special cases in json (self-referencing loops, etc) //settings.ContractResolver = new CustomJsonResolver(); _settings = settings; } return _settings; } } }
WebApiConfig:
public static void Register(HttpConfiguration config) { GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter); GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); GlobalConfiguration.Configuration.Formatters.Add(new CustomJsonMediaTypeFormatter()); ODataModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Category>("Category"); config.MapODataServiceRoute( routeName: "ODataRoute", routePrefix: "odata", model: builder.GetEdmModel()); }
The tutorial about Using JSON.NET with ASP.NET Web API in the below:
https://code.msdn.microsoft.com/Using-JSONNET-with-ASPNET-b2423706
Best Regards,
Yohann Lu
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Tuesday, February 23, 2016 6:45 AM