更改 WCF 中的默认日期序列化

问题描述 投票:0回答:5

有没有办法更改 WCF 中 DateTime 的默认 JSON 序列化/反序列化?

目前,DateTime 被序列化为

/Date(1372252162657+0200)/
格式,这应该没问题,但当我的服务器不在 UTC 时(我无法更改),我遇到了问题。

此服务正在处理的所有日期/时间数据均采用 UTC 格式。当服务器处于 UTC 时,一切正常。但是,staging/prod 环境设置为 GMT+1(Paris),序列化程序假设日期/时间为 GMT+1,完全忽略属性

Kind
。因此,正如您所期望的那样,调用
DateTime.SetKind()
并将其设置为 UTC 是行不通的。实际上,序列化时间延迟了一个小时。

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

c# json wcf datetime serialization
5个回答
24
投票

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

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

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

enter image description here

注意

UpdateDateOriginal
字段,这是 WCF 编写日期时间的默认方式,以及更友好的
UpdateDate
字段,这是我使用下面的代码创建的。

我原来的台词是这样的:

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

...这是创建新的更友好

UpdateDate
JSON值的行。

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

实际上,您可能会发现以 ISO8601 格式返回

DateTime
值更有用。例如:

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

为此,只需使用我上面的代码,但将字符串

"MMM/dd/yyyy HH:mm"
更改为
"s"
在两个地方。

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

获取用户本地时区的日期时间

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


13
投票

你可以使用这个解决方法,在你的 json 对象定义中

[IgnoreDataMember]
public DateTime dateObject;

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

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


4
投票

是的,这可以使用称为“Message Formatters”的概念来完成

但是 Message Formatter 很难解释堆栈溢出。 你可以参考WCF Extensibility : Message Formatters

如果你不想搞砸这个,那么可以使用 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 将跳过序列化的流输出并将其按原样传递给您的客户端。

我希望你得到你的答案。


1
投票

这并不能解决您的时区问题,但我会在此处发布给正在与 WCF、ticks 和 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); } }

0
投票

一种方法是使用消息格式化程序来更改默认值

DataContractSerializer
,如WCF 扩展性 - 消息格式化程序中所述。

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

© www.soinside.com 2019 - 2024. All rights reserved.