如何使用wsdl自动生成的类覆盖C#DateTime序列化?

时间:2010-04-20 20:06:52

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

我有一个WSDL,我的Web服务的消费者期望严格遵守。我将它转换为与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>
...

注意模式的最后一部分,如果包含它们,则subseconds必须是1或7个字符。客户似乎拒绝回复,因为它与该要求不符。

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

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

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

更新 我试图尽早实现IXmlSerializable,正如约翰建议的那样,并得到以下错误: System.InvalidOperationException: There was an error reflecting type '[...].GetCurrentTimeResponse'. ---> System.InvalidOperationException: Only XmlRoot attribute may be specified for the type [...].GetCurrentTimeResponse. Please use XmlSchemaProviderAttribute to specify schema type. 在那之后,我想我必须根据自己的喜好破解生成的代码并继续搜索其他解决方案。

3 个答案:

答案 0 :(得分:1)

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

我相信您必须在IXmlSerializable课程上实施GetCurrentTimeResponse。你可以这样做,因为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");
    }
}

答案 1 :(得分:1)

可能不是原始问题的最相关答案,但由于我在寻找控制序列化中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

答案 2 :(得分:0)

我是个白痴!

首先,正则表达式意味着“介于1到7位之间”而不是“1或7位”,尽管在我的辩护中,the internet是错误的。响应未验证的原因是它在结尾处缺少表示UTC的“Z”。

解决方案就像这样简单:

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

它自己解决了!

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