I'm using ASP.NET Web API. I have the following code and the dates in the response
IEnumerable<StripeInvoice>
aren't being converted to ISO 8601 format when serializing to JSON. They are in the Microsoft .NET format like this /Date(1412657602)/
. Using IsoDateTimeConverter()
should convert to ISO 8601 format such as 2011-07-14T19:43:37+0100
. Why isn't this working for IEnumerable<StripeInvoice>
?
IEnumerable<StripeInvoice> response = service.List();
string json = JsonConvert.SerializeObject(response, new IsoDateTimeConverter());
EDIT
Here is the full method from my Web API controller.
public IEnumerable<StripeInvoice> GetUserInvoices(string id)
{
var options = new StripeInvoiceListOptions()
{
CustomerId = id
};
// Using https://github.com/jaymedavis/stripe.net stripe library
var invoiceService = new StripeInvoiceService();
invoiceService.ApiKey = "key";
IEnumerable<StripeInvoice> response = invoiceService.List(options);
// test
IEnumerable<SomeObject> objs = new SomeObject[] {
new SomeObject() { SomeDate = DateTime.Now.AddDays(-1) },
new SomeObject() { SomeDate = DateTime.Now }
};
// return objs; // this serialized the dates properly into ISO 8601
return response; // this doesn't serialize to ISO 8601. It remains in /Date(142657602)/
}
The problem is that the StripeInvoice
class in the Stripe.Net library is marked up with [JsonConverter]
attributes such that all DateTime
properties use a StripeDateTimeConverter
. That converter always writes out dates in the form /Date(1412657602)/
, as you can see in the source code. Presumably, this is to allow the class to work correctly with the Stripe REST API, which clearly does not use ISO 8601 dates.
You have a few options to solve this:
StripeInvoice
to your own version of Invoice
class and return that from your Web API instead of passing the StripeInvoice
directly through to consumers. Honestly, this is probably your best option, because it separates the concerns of your data source (Stripe) from the concerns of your own API. You could potentially use something like AutoMapper to help copy the data.IContractResolver
to dynamically replace the StripeDateTimeConverter
in the Stripe.Net classes with an IsoDateTimeConverter
when you serialize them in your Web API (see update below).StripeDateTimeConverter
on or off depending on context. This is arguably the worst option of the three, because every time the library gets updated you would have to reapply your custom changes.UPDATE
If you are interested in the second approach, here is a possible implementation for the contract resolver:
class ForceIsoDateTimeResolver : DefaultContractResolver
{
private JsonConverter dateConverter = new IsoDateTimeConverter();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
// For any DateTime property on any class, replace the
// existing converter with an IsoDateTimeConverter.
if (prop.PropertyType == typeof(DateTime) ||
prop.PropertyType == typeof(DateTime?))
{
prop.Converter = dateConverter;
}
return prop;
}
}
To install this resolver into your Web API project, add the following to the Register
method of the WebApiConfig
class (in the App_Start
folder of your Web API project):
JsonSerializerSettings settings = config.Formatters.JsonFormatter.SerializerSettings;
settings.ContractResolver = new ForceIsoDateTimeResolver();