WCF客户端如何从JSON响应中反序列化不兼容的日期格式?

7
我已经在网上搜索了大量关于此事的信息,但大多数结果都是关于创建WCF服务或服务在您控制下的情况。
我正在为一个不在我控制范围内的RESTful JSON服务构建WCF客户端代理。我正在使用基本的ServiceContract/DataContract模式,并尝试让框架尽可能地完成更多的工作。
大多数情况下这很好用,但来自这个外部服务的所有日期时间字段都是特定格式,例如:
{"SomeObject": 
    {"details":"blue and round", "lastmodified":"2013/01/02 23:14:55 +0000"}
}

因此,我得到了一个错误:

反序列化MyNamespace.SomeObject类型对象时发生错误。 DateTime内容 '2013/01/02 23:14:55 +0000' 不以'/Date('开始且不以')/'结尾,这是JSON所要求的。'

我的数据合同是:

namespace Marshmallow.WebServices.ServiceModels
{
    [DataContract]
    public class SomeObject
    {
        [DataMember(Name = "details")]
        public string Details { get; set; }

        [DataMember(Name = "lastmodified")]
        public DateTime LastModified { get; set; }
    }
}

我的服务合同是:

[ServiceContract]
public interface ICoolExternalApi
{
    [OperationContract]
    [WebGet(UriTemplate = "/something.json",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Wrapped)]
    [return: MessageParameter(Name = "SomeObject")]
    SomeObject GetAccount();
}

我想知道的是,在哪里可以添加一些代码来定义WCF如何反序列化lastmodified字段(将字符串转换为DateTime对象)?
或者更好的方法是,定义如何反序列化所有数据合同的DateTime DataMembers。我不想有很多重复的代码。
我也不想使用第三方反序列化器,也不想通过自定义反序列化方法来处理其他所有内容,如果可以避免的话。

将对象反序列化为字符串确实有您所指出的限制。它可以工作,但远非优雅。设置IDispatchMessageInspector需要更多的努力,但应该更加清晰。 - Mike Parkhill
1
我觉得使用IDispatchMessageInspector并不是很优雅。A)正则表达式速度较慢,不太可扩展。B)这是对整个JSON主体的额外解析。C)我必须将日期时间字符串转换为“那个”格式“/Date(1297293089984-0800)/”,然后再次解析以填充DataMember(双重处理)。D)这是一个hack。肯定有另一个WCF功能,我不理解(OnDeserializing或其他什么),旨在处理这些情况吧? - Jordan Morris
2个回答

2

我能想到两件事:

  1. 将LastModified更改为字符串,然后自己将其转换为DateTime对象。但这意味着您的对象需要暴露两个相同数据的属性。
  2. 编写IDispatchMessageInspector以在反序列化之前拦截消息并使用正则表达式处理原始消息。这将允许您在服务中一站式解决所有日期问题。

  1. 到目前为止,这就是我所做的,同时保持字符串属性内部。然而,对于每个DateTime DataMember需要额外编写代码,因此对我来说这很糟糕。
  2. 虽然这样可以工作,但感觉像是一个hack,并且引入了开销,会影响可扩展性。
- Jordan Morris

1
迄今为止,这是我想到的最好方法:
我有一个内部字符串扩展方法:
internal static class DeserializationHelper
{
    internal static DateTime GetDeserializedDateTime(this string @string)
    {
        if (string.IsNullOrEmpty(@string)) return default(DateTime);
        //insert complex custom deserialization logic here
        return DateTime.Parse(@string);
    }

}

这是DataMember的设置:
[DataMember(Name = "lastmodified")]
internal string _LastModified 
{
    set { LastModified = value.GetDeserializedDateTime(); }
    //getter is not needed for receiving data but WCF requires one
    get { return default(string); }
}

public DateTime LastModified { get; private set; }

如果您想使用此DataContract发送数据(将其作为可写属性),则需要编写一个DateTime扩展方法(GetSerializedDateString),扩展setter/getter并引入私有成员作为中间人。
这似乎是剪切和粘贴,而且没有利用任何WCF框架功能。比尔·盖茨会怎么做呢?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接