DataContractJsonSerializer Date Serialization - c#

Is there a way to change how the DataContractJsonSerializer serializes dates?
Currently, it'll convert a date to something like:
{
"date": "/Date(1260597600000-0600)/"
}
I want to convert it into human readable date format.
I am building a RestApi using openrasta framework. Can i write OperationInterceptors which will at some stage before serialization/deserialization convert JSON datetime format to something which is human readable?Or is there any other way to do it?

Use DataContractJsonSerializer constructor to pass your serialization settings:
var s = new DataContractJsonSerializer(
typeof(YourTypeToSerialize),
new DataContractJsonSerializerSettings
{
DateTimeFormat = new DateTimeFormat("yyyy-MM-dd'T'HH:mm:ss")
}
);

Finally i have handled this issue as below(c#)
[DataMember]
public string Date { get; set; }
[IgnoreDataMember]
public DateTime? DateForInternalUse { get; set; }
[OnSerializing]
public void OnSerializing(StreamingContext context)
{
Date = (DateForInternalUse != null) ? ((DateTime)DateForInternalUse).ToString(DateTimeFormatForSerialization) : null;
}
[OnDeserialized]
public void OnDeserialized(StreamingContext context)
{
try
{
DateForInternalUse = !String.IsNullOrEmpty(Date) ? DateTime.ParseExact(Date, DateTimeFormats, null, DateTimeStyles.None) : (DateTime?)null;
}
catch (FormatException)
{
DateForInternalUse = null;
}
}
In this case we can specify the formats which we want to support which i have kept inside web.config
<add key="DateTimePattern" value="yyyy-MM-dd,yyyy-MM-dd hh:mm:ss zzz,yyyy-MM-dd hh:mm:ss" />
Let me know for further clarifications.

Related

Asp.Net MVC web API forcing UTC conversion on dateTime

On my API(ASP.Net, .NET Framework 4.5), I need to return datetime in this format: 2020-06-19T13:30:44+00:00
So I created a new converter
public class JsonDateFormatConverter : IsoDateTimeConverter
{
public JsonDateFormatConverter(string format)
{
DateTimeFormat = format;
}
}
And decorated my models:
[JsonConverter(typeof(JsonDateFormatConverter), "yyyy-MM-ddTHH:mm:sszzz")]
public DateTime? StartDate{ get; set; }
But instead of returning the for examle "2020-03-07T00:00:00+01:00" im getting "2020-03-06T23:00:00Z"
So it seems that everything is being converted to UTC before serialization to JSON.
I tried setting this in WebApiConfing
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local;
But that did not help.
Also tried setting the dateTime kind like this:
[JsonConverter(typeof(JsonDateFormatConverter), "yyyy-MM-ddTHH:mm:sszzz")]
public DateTime? StartDate
{
get => startDate;
set
{
if (value != null)
startDate= DateTime.SpecifyKind(value.Value, DateTimeKind.Local);
else
startDate= value;
}
}
private DateTime? startDate;
Also didnt help.

datetime field in json deserialization

I have a .json like this:
[
{
"number":"00000001",
"dt_doc":"2019-09-26T17:39.000Z",
"address":"complete address"
}
]
But I've got problem with the field dt_doc, this is my deserialization code...
I have this in the main:
public override void CreateNewOutputRows()
{
String jsonFileContent = File.ReadAllText(Variables.JsonFilePath);
JavaScriptSerializer js = new JavaScriptSerializer();
List<Testata> testata = js.Deserialize<List<Testata>>(jsonFileContent);
foreach(Testata test in testata)
{
Output0Buffer.AddRow();
Output0Buffer.number= test.number;
Output0Buffer.dtdoc = test.dt_doc;
Output0Buffer.address= test.address;
}
}
and in my class Testata.cs I have defined the field in this way:
public DateTime dt_doc { get; set; }
But I got an exception on this field, probably related to 8601 standard, is there any way to solve?
This is the exception:
Error: System.FormatException: 2019-09-26T17:39.000Z it's not a valid value for DateTime. ---> System.FormatException: String not recognized as valid DateTime value.
The error is because you are missing seconds in date
"dt_doc":"2019-09-26T17:39.000Z"
should be
"dt_doc":"2019-09-26T17:39.00.000Z"
If this is intentional then you can specify the format. I have tried this using Newtonsoft.Json
public class Testata
{
[JsonConverter(typeof(DateFormatConverter), "yyyy-MM-ddTHH:mm.fffZ")]
public DateTime dt_doc { get; set; }
}
public class DateFormatConverter : IsoDateTimeConverter
{
public DateFormatConverter(string format)
{
DateTimeFormat = format;
}
}
List<Testata> testata = JsonConvert.DeserializeObject<List<Testata>>(jsonString);
you could read it in your class as a string and then:
DateTime.ParseExact(test.dt_doc,"yyyy-MM-ddTHH:mm.fffZ");

XmlSerializer does not account for local timezone when deserializing property annotated with XmlElement with DataType time

When I deserialize a time string, using XmlSerializer.Deserialize, I expect it to take my local timezone into account so that a time string in the format
00:00:00.0000000+01:00
was parsed as 00:00, because I am in the timezone GMT+1.
Did I get that wrong?
Here is the code I am running to test xml deserialization:
using System;
using System.IO;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Testing
{
[TestClass]
public class FooTest
{
[TestMethod]
public void Test()
{
var serializer = new XmlSerializer(typeof(Foo),
new XmlRootAttribute("Foo"));
var xml = "<Foo><TheTime>00:00:00.0000000+01:00</TheTime></Foo>";
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
var f = (Foo) serializer.Deserialize(stream);
Assert.AreEqual("00:00", f.TheTime.ToShortTimeString()); // actual: 01:00
}
[Serializable]
public class Foo
{
[XmlElement(DataType = "time")]
public DateTime TheTime { get; set; }
}
}
}
Unfortunately, there is no built-in type that you can deserialize a xs:time value into when it includes an offset (which is optional in the XSD spec).
Instead, you'll need to define a custom type and implement the appropriate interfaces for custom serialization and deserialization. Below is a minimal TimeOffset struct that will do just that.
[XmlSchemaProvider("GetSchema")]
public struct TimeOffset : IXmlSerializable
{
public DateTime Time { get; set; }
public TimeSpan Offset { get; set; }
public static XmlQualifiedName GetSchema(object xs)
{
return new XmlQualifiedName("time", "http://www.w3.org/2001/XMLSchema");
}
XmlSchema IXmlSerializable.GetSchema()
{
// this method isn't actually used, but is required to be implemented
return null;
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
var s = reader.NodeType == XmlNodeType.Element
? reader.ReadElementContentAsString()
: reader.ReadContentAsString();
if (!DateTimeOffset.TryParseExact(s, "HH:mm:ss.FFFFFFFzzz",
CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto))
{
throw new FormatException("Invalid time format.");
}
this.Time = dto.DateTime;
this.Offset = dto.Offset;
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
var dto = new DateTimeOffset(this.Time, this.Offset);
writer.WriteString(dto.ToString("HH:mm:ss.FFFFFFFzzz", CultureInfo.InvariantCulture));
}
public string ToShortTimeString()
{
return this.Time.ToString("HH:mm", CultureInfo.InvariantCulture);
}
}
With this defined, you can now change the type of Foo.TheTime in your code to be a TimeOffset and your test will pass. You can also remove the DataType="time" in the attribute, as it's declared in the object itself via the GetSchema method.

DotnetNuke Web Api - JsonConverter does not get used

I'm trying to enforce a use of an IsoDateTimeConverter on a specific property.
I register the routes and the Content Negotiator:
public class RouteMapper : IServiceRouteMapper
{
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapHttpRoute("SbApi", "default", "{controller}/{action}", new[] { "SbApi.Controllers" });
GlobalConfiguration.Configuration.Services.Replace(typeof(System.Net.Http.Formatting.IContentNegotiator), new JsonContentNegotiator());
}
}
public class JsonContentNegotiator : IContentNegotiator
{
public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
{
var formatter = new JsonMediaTypeFormatter();
formatter.UseDataContractJsonSerializer = false;
var isoDateConverter = formatter.SerializerSettings.Converters
.OfType<IsoDateTimeConverter>()
.FirstOrDefault();
if(isoDateConverter!=null){
formatter.SerializerSettings.Converters.Remove(isoDateConverter);
}
formatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "dd-MM-yyyy" }); // custom date format, to see if the converter is used
var result = new ContentNegotiationResult(formatter, new MediaTypeHeaderValue("application/json"));
return result;
}
}
Attribute used on the property:
[JsonConverter(typeof(IsoDateTimeConverter))]
public System.DateTime EndDate { get; set; }
The output of the serializer:
"EndDate":"2016-01-01T00:00:00"
How do I make it use the IsoDateTimeConverter?
Edit:
I used a custom IContentNetogiator to enforce use of JSON over XML.
I used the custom datetime format just to see if the converted gets actually used.
What I really need is an ISO format (with the full timezone) but I'm not able to enforce it for some reason. I tried setting it up in the CustomDate, but to no avail.
public CustomDatetimeConverter()
{
base.DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; // none of these work..
base.DateTimeFormat = "o";
base.Culture = System.Globalization.CultureInfo.InvariantCulture;
base.DateTimeStyles = System.Globalization.DateTimeStyles.AssumeLocal;
}
Edit 2:
Anyway, I got it working, sort of. Since nothing was working and I don't need the millisecond part of the time, I ended using the following format: "yyyy'-'MM'-'dd'T'HH':'mm':'ss.000000zzz" .
The "zzz" is used in place of "K" which for some reason doesn't work.
There are a couple of ways to solve this. Neither involves replacing the IContentNegotiator. The first (and easiest) way is to create a subclass of the IsoDateTimeConverter having your custom date format:
class CustomDateTimeConverter : IsoDateTimeConverter
{
public CustomDateTimeConverter()
{
base.DateTimeFormat = "dd-MM-yyyy";
}
}
Then change the [JsonConverter] attribute on your EndDate property:
[JsonConverter(typeof(CustomDateTimeConverter))]
public System.DateTime EndDate { get; set; }
Another way to do the same thing is to create a custom IContractResolver that will apply the IsoDateTimeConverter to your target property programmatically. Below is the code you would need for the resolver. Replace Your_Class with the name of the class containing the EndDate property.
class CustomResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type,
Newtonsoft.Json.MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
if (type == typeof(Your_Class))
{
JsonProperty prop =
props.Where(p => p.PropertyName == "EndDate")
.FirstOrDefault();
if (prop != null)
{
prop.Converter =
new IsoDateTimeConverter { DateTimeFormat = "dd-MM-yyyy" };
}
}
return props;
}
}
To install this resolver in your project, add the following line to the Register method of your WebApiConfig class:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
new CustomResolver();

Serializing a DataType="time" field using XmlSerializer

I'm getting an odd result when serializing a DateTime field using XmlSerializer.
I have the following class:
public class RecordExample
{
[XmlElement("TheTime", DataType = "time")]
public DateTime TheTime { get; set; }
[XmlElement("TheDate", DataType = "date")]
public DateTime TheDate { get; set; }
public static bool Serialize(
Stream stream, object obj, Type objType, Encoding encoding)
{
try
{
var settings = new XmlWriterSettings { Encoding = encoding };
using (var writer = XmlWriter.Create(stream, settings))
{
var xmlSerializer = new XmlSerializer(objType);
if (writer != null) xmlSerializer.Serialize(writer, obj);
}
return true;
}
catch (Exception)
{
return false;
}
}
}
When i call the use the XmlSerializer with the following testing code:
var obj = new RecordExample
{
TheDate = DateTime.Now.Date,
TheTime = new DateTime(0001, 1, 1, 12, 00, 00)
};
var ms = new MemoryStream();
RecordExample.Serialize(ms, obj, typeof(RecordExample), Encoding.UTF8);
txtSource2.Text = Encoding.UTF8.GetString(ms.ToArray());
I get some strange results, here's the xml that is produced:
<?xml version="1.0" encoding="utf-8"?>
<RecordExample
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TheTime>12:00:00.0000000+00:00</TheTime>
<TheDate>2010-03-08</TheDate>
</RecordExample>
Any idea's how i can get the "TheTime" element to contain a time which looks more like this:
<TheTime>12:00:00.0Z</TheTime>
...as that's what i was expecting?
Thanks
Dave
I've had different issues with this myself... however I was attempting to serialize a TimeSpan object. The solution was to have two properties, one that held the TimeSpan, and one that was a string representation of the TimeSpan which got Serialized. Here was the pattern:
[XmlIgnore]
public TimeSpan ScheduledTime
{
get;
set;
}
[XmlElement("ScheduledTime", DataType="duration")]
public string XmlScheduledTime
{
get { return XmlConvert.ToString(ScheduledTime); }
set { ScheduledTime = XmlConvert.ToTimeSpan(value); }
}
However, with this code, the time is printed out in the following format:
<ScheduledTime>PT23H30M</ScheduledTime>
The W3C definition of duration is here which explains it.
take a look at this question Serializing DateTime to time without milliseconds and gmt
Expanding on the comment I made on one of the others answers.
public class RecordExample : IXmlSerializable
{
public DateTime TheTime { get; set; }
public DateTime TheDate { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
// TODO : Deserialization logic here
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString(
"date",
this.TheDate.ToString("yyyy-MM-dd"));
writer.WriteElementString(
"time",
this.TheTime.ToString("hh:mm:ss.fK"));
}
}
Serializing like this:
var rc = new RecordExample()
{
TheDate = DateTime.Today,
TheTime = DateTime.UtcNow
};
var serializer = new XmlSerializer(typeof(RecordExample));
var ms = new MemoryStream();
serializer.Serialize(ms, rc);
ms.Seek(0, SeekOrigin.Begin);
Console.WriteLine(new StreamReader(ms).ReadToEnd());
Output example:
<?xml version="1.0"?>
<RecordExample>
<date>2010-03-08</date>
<time>04:26:16.1Z</time>
</RecordExample>
I concur with the other answers (I was not done writing when they popped up). it does not look like it is possible, in a direct way.
A look at the source with Reflector shows that a time value ends up being converted to a string with the System.Xml.XmlConvert.ToString, that has a hard-coded format of:
HH:mm:ss.fffffffzzzzzz
So having two properties, the real one being [XmlIgnore] and a string that you build yourself is a good way to go.

Categories

Resources