有没有办法更改 WCF 中 DateTime 的默认 JSON 序列化/反序列化?
目前,DateTime 被序列化为
/Date(1372252162657+0200)/
格式,这应该没问题,但当我的服务器不在 UTC 时(我无法更改),我遇到了问题。
此服务正在处理的所有日期/时间数据均采用 UTC 格式。当服务器处于 UTC 时,一切正常。但是,staging/prod 环境设置为 GMT+1(Paris),序列化程序假设日期/时间为 GMT+1,完全忽略属性
Kind
。因此,正如您所期望的那样,调用 DateTime.SetKind()
并将其设置为 UTC 是行不通的。实际上,序列化时间延迟了一个小时。
我可以进行双向日期对话(它在反序列化时也做出相同的假设,所以它总是 GMT+1)日期对话:UTC 到/从服务器时间,但这太乏味了。所以我想也许我可以覆盖默认的序列化行为。
只是为了扩展tdelepine的代码片段,这里是我使用的代码:
在我的 WCF JSON 服务中,我有一个(可为空的)DateTime 值,并希望我的服务以更具可读性的格式返回日期,以便我的 iPhone 应用程序能够解释它。
这是我的 JSON 在应用一些更改后的样子:
注意
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 服务返回用户本地时区中的值,您可以按照我的提示操作:
举几个简单的例子,生活是不是更轻松了!
你可以使用这个解决方法,在你的 json 对象定义中
[IgnoreDataMember]
public DateTime dateObject;
public string dateCustomSerialize
{
get {
//Custom get
}
set {
//Custom set
}
}
在评估员中放置您的自定义格式序列化
是的,这可以使用称为“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 将跳过序列化的流输出并将其按原样传递给您的客户端。
我希望你得到你的答案。
这并不能解决您的时区问题,但我会在此处发布给正在与 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); } }
一种方法是使用消息格式化程序来更改默认值
DataContractSerializer
,如WCF 扩展性 - 消息格式化程序中所述。
另一个选择是编写一个扩展方法,将你的对象加载到一个流中,然后你可以将任何你想要的序列化程序应用于该对象。有关如何执行此操作的详细信息,请参阅将 WCF 4 中的默认 JSON 序列化程序替换为 JSON.NET 的已接受答案。