【问题标题】:How to override C# DateTime serialization with class auto-generated from wsdl?如何使用从 wsdl 自动生成的类覆盖 C# DateTime 序列化?
【发布时间】:2010-04-20 20:06:51
【问题描述】:

我有一个 WSDL,我的 Web 服务的使用者希望严格遵守该 WSDL。我将它转换为带有 wsdl.exe 的接口,并让我的 Web 服务实现它。除了这个问题,我对结果总体上很满意。

一个简单的 GetCurrentTime 方法将具有从接口定义中的 WSDL 生成的以下响应类:

[System.CodeDobmCompiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="[Client Namespace]")]
public partial class GetCurrentTimeResponse {
    private System.DateTime timeStampField;

    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified]
    public System.DateTime TimeStamp{
        // [accesses timeStampField]
    }
}

当我将响应数据放入自动生成的响应类时,它会被序列化为适当的 XML 响应。 (大多数 Web 方法的返回类型要复杂得多,具有多级数组。)

问题在于 DateTime 对象的默认序列化违反了 WSDL 中的要求之一:

...
<xsd:simpleType name="SearchTimeStamp">
  <xsd:restriction base="xsd:dateTime">
    <xsd:pattern value="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{1,7})?Z">
  </xsd:restriction>
</xsd:simpleType>
...

注意模式的最后一部分,如果包含亚秒,则亚秒必须是 1 或 7 个字符。客户端似乎拒绝响应,因为它不符合该要求。

主要问题是,当 .NET 序列化 DateTime 对象时,它会省略所有尾随零,这意味着生成的亚秒值的长度会有所不同。 (例如,“12:34:56.700”默认序列化为“&lt;TimeStamp&gt;12:34:56:7&lt;/TimeStamp&gt;”)。我们使用毫秒精度,因此我需要将所有时间戳格式化为 7 个亚秒数字,以符合 WSDL。

如果我可以指定格式字符串会很容易,但我不确定如何控制 DateTime 对象用于序列化为 XML 的字符串,或者以其他方式覆盖序列化行为。我该怎么做呢?请记住以下几点...

  • 我想尽可能少地修改生成的代码...如果可以通过部分类或继承类进行更改,最好根本不修改。
  • 使用继承类作为 Web 方法的返回类型将导致 Web 服务不再实现自动生成的接口。
  • TimeStamp 类型出现在其他更复杂的响应类型中。因此,手动覆盖整个序列化过程可能非常耗时。

更新: 正如约翰建议的那样,我在早期尝试实现 IXmlSerializable ,但出现以下错误: System.InvalidOperationException: There was an error reflecting type '[...].GetCurrentTimeResponse'. ---&gt; System.InvalidOperationException: Only XmlRoot attribute may be specified for the type [...].GetCurrentTimeResponse. Please use XmlSchemaProviderAttribute to specify schema type. 在那之后,我认为我不得不根据自己的喜好对生成的代码进行过多的修改,并继续寻找其他解决方案。

【问题讨论】:

  • 一般来说,你不应该得到那个例外。你能展示你的IXmlSerializable 实现吗?

标签: c# .net web-services datetime wsdl


【解决方案1】:

我从未见过 WSDL 中的 XML Schema 对 xsd:dateTime 施加限制。

我相信你必须在你的 GetCurrentTimeResponse 类上实现 IXmlSerializable。由于 C# 的“部分类”特性,您可以这样做。在您的项目中创建另一个文件并添加以下代码:

public partial class GetCurrentTimeResponse : 
    System.Xml.Serialization.IXmlSerializable
{
    public XmlSchema GetSchema() { return null; }

    public void ReadXml(XmlReader reader) {
        // Fill the TimeStamp property here
    }

    public void WriteXml(XmlWriter writer) {
        // Write out TimeStamp.ToString(
        //    System.Globalization.CultureInfo.InvariantCulture, 
        //    "proper format");
    }
}

【讨论】:

  • 很好的回应,谢谢。有关我尝试这种方法时发生的情况的更多信息,请参阅编辑后的问题。另外,请参阅我的回答,了解 XSD 似乎对 dateTime 类型施加限制的原因。
【解决方案2】:

我是个白痴!

首先,正则表达式的意思是“1 到 7 位数字”而不是“1 位或 7 位数字”,尽管在我的辩护中,the internet 是错误的。响应未验证的原因是它在末尾缺少指示 UTC 的“Z”。

解决方案就这么简单:

GetCurrentTimeResponse response = new GetCurrentTimeResponse() {
    TimeStamp = timeStampWeWant.ToUniversalTime()
}

它自己解决了!

<TimeStamp>2010-04-20T20:12:16.674Z</TimeStamp>

【讨论】:

    【解决方案3】:

    可能不是与您的原始问题最相关的答案,但由于我在寻找控制序列化中 DateTime 属性格式的方法时被重定向到此页面,因此其他人可能会发现它很有用。

    我发现通过将以下内容添加到您的 app.config/web.config 可以指示 .NET 序列化以一致地格式化 DateTime 属性:

      <system.xml.serialization>
        <dateTimeSerialization mode="Local" />
      </system.xml.serialization>
    

    参考:http://msdn.microsoft.com/en-us/library/ms229751(v=VS.85).aspx

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      相关资源
      最近更新 更多