【问题标题】:Json.NET IsoDateTimeConverter not working with classes from Stripe.Net libraryJson.NET IsoDateTimeConverter 不适用于 Stripe.Net 库中的类
【发布时间】:2014-10-13 22:26:39
【问题描述】:

我正在使用 ASP.NET Web API。我有以下代码,responseIEnumerable<StripeInvoice> 中的日期在序列化为 JSON 时没有被转换为 ISO 8601 格式。它们采用 Microsoft .NET 格式,例如 /Date(1412657602)/。使用 IsoDateTimeConverter() 应转换为 ISO 8601 格式,例如 2011-07-14T19:43:37+0100。为什么这不适用于IEnumerable<StripeInvoice>

IEnumerable<StripeInvoice> response = service.List();            
string json = JsonConvert.SerializeObject(response, new IsoDateTimeConverter());

编辑

这是来自我的 Web API 控制器的完整方法。

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)/
}

【问题讨论】:

  • 你能提供一个完整的例子来展示这个问题吗?我似乎无法重现您所看到的:dotnetfiddle.net/xus9wM
  • @AndrewWhitaker 您的 dotnetfiddle objs 在 Web API 控制器中工作。我在控制器中使用的 IEnumerable 仍然没有序列化为 ISO 8601。我不知道有什么区别。我将使用我正在使用的更新代码进行编辑。顺便说一句,我正在从名为 Stripe 的支付服务中获取我的IEnumerable 数据。 stripe.com

标签: asp.net json asp.net-web-api json.net stripe.net


【解决方案1】:

问题在于 Stripe.Net 库中的 StripeInvoice 类标记有 [JsonConverter] 属性,因此所有 DateTime 属性都使用 StripeDateTimeConverter。该转换器始终以/Date(1412657602)/ 的形式写出日期,您可以在source code 中看到。据推测,这是为了让该类与 Stripe REST API 正常工作,这显然不使用 ISO 8601 日期。

你有几个选择来解决这个问题:

  1. 最直接的选择是将发票数据从StripeInvoice 复制到您自己版本的Invoice 类,然后从您的Web API 返回,而不是将StripeInvoice 直接传递给消费者。老实说,这可能是您最好的选择,因为它将您的数据源(Stripe)的关注点与您自己的 API 的关注点分开。您可能会使用 AutoMapper 之类的东西来帮助复制数据。
  2. 当您在 Web API 中序列化它们时,应该可以创建自定义 IContractResolver 以将 Stripe.Net 类中的 StripeDateTimeConverter 动态替换为 IsoDateTimeConverter(请参阅下面的更新)。
  3. Stripe.Net 库是开源的;您可以根据自己的需要修改代码,以便可以根据上下文打开或关闭StripeDateTimeConverter。这可以说是三者中最糟糕的选择,因为每次更新库时,您都必须重新应用自定义更改。

更新

如果您对第二种方法感兴趣,这里是合约解析器的可能实现:

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;
    }
}

要将此解析器安装到您的 Web API 项目中,请将以下内容添加到 WebApiConfig 类的 Register 方法(在您的 Web API 项目的 App_Start 文件夹中):

JsonSerializerSettings settings = config.Formatters.JsonFormatter.SerializerSettings;
settings.ContractResolver = new ForceIsoDateTimeResolver();

【讨论】:

  • 谢谢,我已经使用自己的InvoiceDTO 开始了第一个选项,但想知道发生了什么。感谢您指出这一点,我应该知道看看源代码。
  • 没问题。很高兴我能帮上忙。
【解决方案2】:

我遇到了同样的问题,但我通过从 /Date(...)/ 中获取 unix 时间并将该值乘以一千来修复它 最后像这段代码一样使用angular的日期函数。

{{(x.created | limitTo : 10 : 6) * 1000 | date: 'yyyy-MM-dd HH:mm:ss Z' }}

我希望这有助于指导解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多