为什么类型为s:s的XSD元素在生成服务引用时会成为字符串?

时间:2010-06-29 23:14:33

标签: date xsd wsdl svcutil.exe service-reference

我正在尝试从WSDL创建一个新的服务引用,并且我希望所有的属性都是DateTime而不是string。

例如,联系人的xsd定义:

<s:complexType name="Contact">
    <s:sequence>
        <s:element minOccurs="0" maxOccurs="1" name="Address" type="tns:Address" />
        <s:element minOccurs="0" maxOccurs="1" name="Email" type="s:string" />
        ...
        <s:element minOccurs="1" maxOccurs="1" name="BirthDate" type="s:date" />
</s:sequence>

BirthDate的类型是s:date,但生成的类型(在Reference.cs中)是一个字符串。

internal partial class Contact : object, IExtensibleDataObject, INotifyPropertyChanged
{
    [OptionalField]
    private MembershipMgmtMediator.Address AddressField;

    [OptionalField]
    private string EmailField;

    private string BirthDateField;
}

如果我创建一个Web项目并将其添加为Web引用而不是服务引用,它将正确成为DateTime。我认为这与wsdl.exe和svcutil.exe在幕后工作的方式有关,但无论如何,我都在试图弄清楚如何正确地让Visual Studio认识到这个属性应该是一个DateTime。

3 个答案:

答案 0 :(得分:5)

这些问题有一些很好的信息:How to generate xs:Date in WCF OperationContract parameterBest practices for DateTime serialization in .NET 3.5

正如Alex在对该问题的评论中所述,WCF不支持xs:date类型。但是,可能更准确地说默认DataContractSerializer不支持该类型,而上述问题表明XmlSerializer可以处理它。

请参阅此link,了解DataContractSerializerXmlSerializer的对比。

如果我跑:

svcutil http://my_web_site?wsdl /ser:XmlSerializer /d:C:\temp

然后是这样的WSDL片段:

<s:complexType name="Contact">
    <s:sequence>
        <s:element minOccurs="1" maxOccurs="1" name="BirthDate" type="s:date" />
    </s:sequence>
</s:complexType>

是否已生成此类:

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/")]
public partial class Contact
{

    private System.DateTime birthDateField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType="date", Order=0)]
    public System.DateTime BirthDate
    {
        get
        {
            return this.birthDateField;
        }
        set
        {
            this.birthDateField = value;
        }
    }
}

svcutil次调用会生成两个文件:Service1.csoutput.config。如果我在项目中包含代码文件并将system.serviceModel位添加到配置文件(即web.config或app.config)中,我可以正常调用该服务。例如:

Service1SoapClient client = new Service1SoapClient("Service1Soap");
var contact = client.GetContact();

这种方法并非没有缺点。如果在没有Service1.cs参数的情况下生成,则/ser:XmlSerializer文件会有明显的不同,您可以在其中获得其他类,例如WebMethodNameRequestWebMethodNameRequestBodyWebMethodNameReponse,{{1 }} 等等。如果这些类在您与服务的交互中很重要,我的方法可能对您不起作用。

修改

就可空属性而言,这个问题有一些很好的信息:svcutil.exe - Proxy generated not allowing for nullable fields

要在生成的代理类中获取可为空的属性,需要在WSDL中设置WebMethodNameReponseBody字段。所以像这样:

nillable

会在代理类中生成一个名为<s:element minOccurs="0" maxOccurs="1" name="SomeProperty" type="s:date" nillable="true" /> 的属性。

但是在您的情况下,您可以使用public System.Nullable<System.DateTime> SomeProperty属性来指示属性的存在与否。当您拥有SomePropertySpecified时会生成这些类型的属性。

就日期格式而言,我不确定。 minOccurs="0"值应为yyyy-mm-dd,并带有可选的时区信息(w3.org)。如果Oracle期望使用不同格式的日期,那么我想知道它们是如何成为xs:date值的。

您是否可以提供有关您尝试使用的服务的任何文档或其他信息?

编辑2:

我有点不清楚“日期必须是数据库格式”。意味着在Oracle文档中。如果类型是xs:date,那么将它们序列化为数据库格式肯定意味着它不再是xs:date

不过,你在这方面还有一些尝试:

您可能只需要尝试向网络服务发送一些查询,以了解此日期业务对事物的影响。

您确定那些xs:date参数不存在吗?要使用上面的*IsSpecified类作为示例,Contact属性上的minOccurs=0会为BirthDate类提供一个名为Contact的额外属性。

答案 1 :(得分:0)

虽然这不是一个真正的解决方案,但我认为它可以作为一种解决方法。 它很脏又丑,我知道,但它可能比你的代码中有String更好。

由于您自己的类(如Address)已正确处理,因此您可以构建一个包含在项目和模式中的Date类的简单包装器。该类只有Date属性或字段和getter。

答案 2 :(得分:0)

虽然我相信nick_w的答案很好地涵盖了这个问题(而且我正在授予他赏金),但我提供了我将在我的特定情况下使用的解决方案,其中只使用XmlSerializer isn够了。最后,我想我将使用自定义格式说明符将DateTime个对象转换为字符串的扩展名。

public static class SoapUtils
{
    public static string ToOraDate( this DateTime? dt )
    {
        return dt != null ? dt.Value.ToString("dd-MMM-yyyy",
                                              CultureInfo.InvariantCulture) : 
    }
}

// Calling a service
someDate = DateTime.Now;
service.SomeMethod( someDate.ToOraDate() );