Below is the property in my model:
public DateTimeOffset AcquireDate { get; set; }
Below is the configuration in WebApiConfig:
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.Add(new XmlMediaTypeFormatter());
Below is the json response (date is in IS 8601 format):
Below is the XML response:
<AcquireDate xmlns:d3p1="http://schemas.datacontract.org/2004/07/System">
<d3p1:DateTime>2008-01-10T16:40:12.1523923Z</d3p1:DateTime>
<d3p1:OffsetMinutes>330</d3p1:OffsetMinutes>
</AcquireDate>
From fiddler:
In Xml response, datetime and offset are available in two different elements. I want DateTimeOffset as single value, just like json response (in ISO 8601 format).
I could use one more property which would be of type string and that way my problem could be solved (empty setter requires for this property to be serialized).
[DataMember(Name="AcquireDate")]
public string AcquireDateString
{
get
{
return AcquireDate.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz");
}
set {
AcquireDate = DateTimeOffset.Parse(value);
}
}
Any other solution apart from that?
Solution should not affect existing Json Serialization which is working fine.
Let's understand that DateTimeOffset is giving you the UTC time in addition to how much that value differs from UTC. Thus, the value always unambiguously identifies a single point in time. This is very valuable information you may not want to loose. But if because of requirements you must store just the offset, then continue reading the solution below.
Since you have flexibility to change your type from DateTimeOffset to a string, then maybe you can alter the type a bit and still use DateTimeOffset.
For example,
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace ConsoleApplication8
{
public struct Iso8601SerializableDateTimeOffset : IXmlSerializable
{
public DateTimeOffset value;
public Iso8601SerializableDateTimeOffset(DateTimeOffset value)
{
this.value = value;
}
public static implicit operator Iso8601SerializableDateTimeOffset(DateTimeOffset value)
{
return new Iso8601SerializableDateTimeOffset(value);
}
public static implicit operator DateTimeOffset(Iso8601SerializableDateTimeOffset instance)
{
return instance.value;
}
public static bool operator ==(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
{
return a.value == b.value;
}
public static bool operator !=(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
{
return a.value != b.value;
}
public static bool operator <(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
{
return a.value < b.value;
}
public static bool operator >(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
{
return a.value > b.value;
}
public override bool Equals(object o)
{
if (o is Iso8601SerializableDateTimeOffset)
return value.Equals(((Iso8601SerializableDateTimeOffset)o).value);
else if (o is DateTimeOffset)
return value.Equals((DateTimeOffset)o);
else
return false;
}
public override int GetHashCode()
{
return value.GetHashCode();
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
var text = reader.ReadElementString();
value = DateTimeOffset.ParseExact(text, format: "o", formatProvider: null);
}
public override string ToString()
{
return value.ToString(format: "o");
}
public string ToString(string format)
{
return value.ToString(format);
}
public void WriteXml(XmlWriter writer)
{
writer.WriteString(value.ToString(format: "o"));
}
}
public class Foo
{
public Guid Id { get; set; }
[JsonConverter(typeof(UtcDateTimeOffsetConverter))]
public Iso8601SerializableDateTimeOffset AcquireDate { get; set; }
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo {
Id = Guid.NewGuid(),
AcquireDate = DateTimeOffset.Now
};
var xmlSerializer = new System.Xml.Serialization.XmlSerializer(foo.GetType());
xmlSerializer.Serialize(Console.Out, foo);
Console.WriteLine();
Console.ReadLine();
}
}
}
Output
<?xml version="1.0" encoding="IBM437"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Id>830cabe2-340b-42c6-bad4-12b5b8b1c43f</Id>
<AcquireDate>2016-03-14T10:47:51.8162249-04:00</AcquireDate>
</Foo>
For JSON, we need a converter but we can reuse Newtonsoft.Json.Converters.IsoDateTimeConverter
public class UtcDateTimeOffsetConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is Iso8601SerializableDateTimeOffset)
{
var date = (Iso8601SerializableDateTimeOffset)value;
value = date.value;
}
base.WriteJson(writer, value, serializer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object value = base.ReadJson(reader, objectType, existingValue, serializer);
if (value is Iso8601SerializableDateTimeOffset)
{
var date = (Iso8601SerializableDateTimeOffset)value;
value = date.value;
}
return value;
}
}
The controller
public class ValuesController : ApiController
{
public class Foo
{
public Guid Id { get; set; }
[JsonConverter(typeof(UtcDateTimeOffsetConverter))]
public Iso8601SerializableDateTimeOffset AcquireDate { get; set; }
}
// GET api/values
public IEnumerable<Foo> Get()
{
return new Foo[] {
new Foo() {
Id = Guid.NewGuid(),
AcquireDate = DateTimeOffset.Now
}
};
}
}
Output
<ArrayOfFoo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebApplication1.Models">
<Foo>
<AcquireDate>2016-03-14T12:04:30.2791167-04:00</AcquireDate>
<Id>b3188528-f854-454a-bf9f-9822ff27dc6f</Id>
</Foo>
</ArrayOfFoo>
JSON
[{"Id":"e24bc769-3463-4320-b39a-9ff97e709142","AcquireDate":"2016-03-15T10:47:29.3061449-04:00"}]
Full example can be found on github: https://github.com/alexnolasco/DatetimeOffsetXMLSerializationExample
See also: How can I XML Serialize a DateTimeOffset Property?
Choosing Between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With