18

无论如何要更改 WCF 中 DateTime 的默认 JSON 序列化/反序列化?

目前, DateTime 被序列化为/Date(1372252162657+0200)/格式,这应该没问题,但是当我的服务器不在 UTC 时我遇到了问题(我无法更改)。

此服务正在处理的所有日期/时间数据均采用 UTC 格式。当服务器采用 UTC 时,一切正常。但是,staging/prod 环境设置为 GMT+1(Paris) 并且序列化程序假设日期/时间在 GMT+1 中,完全忽略了属性Kind。因此,正如您所期望的那样,调用DateTime.SetKind()并将其设置为 UTC 将不起作用。实际上,序列化时间延迟了一个小时。

我可以进行双向日期对话(它在反序列化时也做出相同的假设,因此它始终为 GMT+1)日期对话:UTC 到/来自服务器时间,但这很乏味。所以我想也许我可以覆盖默认的序列化行为。

4

5 回答 5

23

只是为了扩展tdelepine的代码片段,这里是我使用的代码:

在我的 WCF JSON 服务中,我有一个(可为空的)DateTime 值,并希望我的服务以更易读的格式返回日期,以便我的 iPhone 应用程序能够解释它。

这是我的 JSON 在应用一些更改后的样子:

在此处输入图像描述

请注意该UpdateDateOriginal字段,这是 WCF 编写 DateTimes 的默认方式,以及UpdateDate我使用下面的代码创建的更友好的字段。

我原来的线条是这样的:

[DataMember]
public DateTime? UpdateDateOriginal { get; set; }

...这里是创建新的更友好的UpdateDateJSON 值的行。

[IgnoreDataMember]
public DateTime? UpdateDate { get; set; }

[DataMember(Name = "UpdateDate")]
private string UpdateDateString { get; set; }

[OnSerializing]
void OnSerializing(StreamingContext context)
{
    if (this.UpdateDate == null)
    this.UpdateDateString = "";
    else
    this.UpdateDateString = this.UpdateDate.Value.ToString("MMM/dd/yyyy HH:mm", CultureInfo.InvariantCulture);
}

[OnDeserialized]
void OnDeserializing(StreamingContext context)
{
    if (this.UpdateDateString == null)
    this.UpdateDate = null;
    else
    this.UpdateDate = DateTime.ParseExact(this.UpdateDateString, "MMM/dd/yyyy HH:mm", CultureInfo.InvariantCulture);
}

DateTime实际上,您可能会发现以 ISO8601 格式返回值更有用。例如:

UpdateTime: "2014-08-24T13:02:32",

为此,只需使用我上面的代码,但在两个地方都 将字符串"MMM/dd/yyyy HH:mm"更改为。"s"

而且,如果您的 DateTime 值存储在 UTC 中,但您希望 WCF 服务返回用户本地时区中的值,您可以在此处遵循我的提示:

获取用户本地时区的 DateTime

生活不是更简单,举几个简单的例子!

于 2015-01-09T12:46:51.873 回答
13

您可以使用此解决方法,在您的 json 对象定义中

[IgnoreDataMember]
public DateTime dateObject;

public string dateCustomSerialize
{
 get {
//Custom get
}
set {
//Custom set
}
}

在评估器中放置您的自定义格式序列化

于 2013-08-29T12:50:49.887 回答
4

是的,这可以使用名为“消息格式化程序”的概念来完成

但是消息格式化程序会很困难,并且超出了这里解释堆栈溢出的范围。您可以参考WCF 扩展性:消息格式化程序

如果您不想搞砸这个,那么可以使用 hack。

将每个方法的返回类型设置为 Stream。

例如

        public Stream GetStaticData()
        {
            var objTobeReturned = something;
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
            return new MemoryStream(Encoding.UTF8.GetBytes(objTobeReturned.ToJson()));
        }

这里 ToJson() 是我自己的扩展方法,它使用 NewtonSoft 库将对象转换为 json 字符串。

WCF 将跳过流输出进行序列化,并将其按原样传递给您的客户端。

我希望你得到你的答案。

于 2013-08-29T12:48:21.717 回答
1

这并不能解决您的时区问题,但我会将其发布在此处,以供其他与 WCF、滴答声和 DateTime 作斗争的人使用。

如果您不想要刻度,而是人类可读的时间格式,您可以通过引入一个附加string属性来实现。DateTime然后就是在将值转换为字符串之前摆弄一下。

    [IgnoreDataMember]    // Ignore the original tick date.
    public DateTime LastReminderDate { get { return _lastReminderDate; } set { _lastReminderDate = value; } }
    [DataMember]          // Make sure you have a public or private setter!
    public string LastReminderDateText { get { return _lastReminderDate.ToString(); } set { _lastReminderDate = DateTime.Parse(value); } }
于 2017-12-01T17:02:31.650 回答
0

一种方法是使用消息格式化程序来更改默认值DataContractSerializer,如WCF 可扩展性 – 消息格式化程序中所述。

另一种选择是编写一个扩展方法,将您的对象加载到流中,然后您可以将任何您想要的序列化程序应用于对象。有关如何执行此操作的详细信息,请参阅将WCF 4 中的默认 JSON 序列化程序替换为 JSON.NET的已接受答案。

于 2013-08-29T12:49:59.063 回答