65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 对 xs:date 的支持

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (4投票s)

2011年4月17日

CPOL

4分钟阅读

viewsIcon

49533

downloadIcon

775

WCF 与其他框架在传输日期值时的互操作性

引言

尽管 WCF 技术强大且灵活,但在某些方面仍有改进的空间。在本文中,我将展示与 Web 服务的日期格式互操作性相关的问题以及如何解决这些问题。

背景

我的公司是一家金融机构,有许多不同的应用程序交换数据。其中大多数应用程序都是用 Java 实现的,而我的应用程序公开了用 WCF .NET 实现的 Web 服务。

为了交换日期,我提出了一个 xs:dateTime 格式。 这是因为那时我还不了解这种类型的特殊性。

第一个问题:UTC 格式。 当我使用 soapUI 测试 Web 服务时,我手动输入了 1969-03-17T00:00:00.000+01:00 作为 1969-03-17 出生日期的输入参数。 一切都很好。 然而,当实际的 Web 服务客户端发送 1969-03-16T23:00:00.000Z(UTC 格式的等效日期时间)时,.NET 将其视为 1969-03-16 日期(偏移一天)。

补充说明:我在波兰工作,所以冬天是 GMT+1,夏天是 GMT+2 CET 时区,具有夏令时。

因此,看起来 UTC 时间没有被正确处理。 幸运的是,存在一个简单的解决方法

if (date.Kind == DateTimeKind.Utc) 
date = date.ToLocalTime()    

第二个更困难的问题如下:对于某些日期值,不同的框架有不同的表示形式。 例如,我的 WCF Web 服务接收到 1941-12-05T00:00:00.000+02:00。 Java 客户端的意图是发送 1941-12-05 日期,而 .NET 服务将其视为 1941-12-04。 我们发现大约 5% 的日期存在类似的问题。 这些日期大多来自 40 年代,但不仅仅如此。 一种可能的解释是 夏令时 在 40 年代没有使用。 或者也许一个框架使用了 德国的夏令时 用于二战时期?

如果您开始考虑框架之间的夏令时差异,那么以这种方式表示日期的想法就会变得疯狂。 那么框架是否必须记住夏令时期的历史日期? 他们是否考虑了历史事故,例如改变边界(和时区)? 哪里有记载? 如果算法不同怎么办? 哪些参数会影响时区解释? 我们知道最重要的是 Windows 上的区域设置。 Linux、AIX 呢? 所有服务器都具有正确且兼容的设置吗?

好的,所以 xs:dateTime 不是一个好的选择,因为框架之间存在差异。 还有哪些其他选择? xs:string 呢? 不幸的是,这也不是一个好的选择:目前使用着许多不同的格式:dd-MM-yyyy、yyyy-MM-dd、yyyyMMdd、… 。 在某些情况下,这是可以的——例如一个 Web 服务对应一个客户端。 但在某些情况下,这是不够的:当来自多个系统的 Web 服务在 ServiceBus 上重用以创建新的 Web 服务时,所有 Web 服务都必须同意一种格式。 但是,有时无法更改格式,因为许多客户端都在使用它。

最好的选择是使用没有时区的 xs:date (xs:date 可用的选项)。 但是在 WCF 中,不支持此选项。 我在 Google 上搜索了很多,但没有找到令人满意的解决方案。 好的,我发现可以强制 WCF 使用能够使用 xs:dateXmlSerializer。 但我更喜欢使用 DataContractSerializer,因为其他原因。 最重要的是:XmlSerializer 不会处理简单服务参数的 xs:dateXmlSerializer 要求日期必须是对象的属性。

那么我的建议是什么? 我找到了以下解决方案:定制的 xs:date。 它并不像看起来那么复杂。

Using the Code

我定义了自己的类型 – WcfDate,它实现了 IXmlSerializable 接口。 在服务合同中,使用该类型代替 .NET 代码中的 DateTime 就足够了。

例如

[ServiceContract]
public interface IService1
{
    [OperationContract]
    string GetData(WcfDate value);
    
    [OperationContract]
    CompositeType GetDataUsingDataContract(CompositeType composite);
}

[DataContract]
public class CompositeType
{
    bool boolValue = true;
    string stringValue = "Hello ";
    WcfDate dateValue = new WcfDate(DateTime.Today);
    
    [DataMember]
    public bool BoolValue
    {
        get { return boolValue; }
        set { boolValue = value; }
    }
    
    [DataMember]
    public string StringValue
    {
        get { return stringValue; }
        set { stringValue = value; }
    }
    
    [DataMember]
    public WcfDate DateValue
    {
        get { return dateValue; }
        set { dateValue = value; }
    }
}       

在运行时,WcfDate 在 soap envelop 中呈现为 xs:date。 我还添加了一些扩展方法,以便轻松地在 WcfDateDateTime 之间进行转换。 例如,可以在一行中递增传入的日期

composite.DateValue = composite.DateValue.GetDate().AddDays(1).ToWcfDate();    

所有详细信息都在附加的代码中:WcfCommon 项目提供了 WcfDate 类型和 WsdlDocumentation 属性(从 Microsoft 示例复制)以及 WcfSampleService 展示了如何使用 WcfDate

缺点

当您生成代理时,客户端不支持 xs:date。 然后 xs:date 元素被视为 xs:string。 客户端必须自己解析 date,但这仍然比以前好,因为 xs:date 强制执行标准的 date 布局。

进一步的结论

Date 类型非常有用。 它存在于大多数数据库(包括 SQL Server)以及许多框架和语言中(尽管并非全部)。 如果 Microsoft 在 WCF 和 .NET Framework 中原生支持它,我们的生活会更轻松。

历史

  • 2011 年 4 月 15 日:初版
© . All rights reserved.