为什么WCF将Enum序列化为字符串?

时间:2010-07-06 20:09:36

标签: vb.net wcf

服务器上的代码

<DataContract(Namespace:="http://schema.aam.us.com/2010/6", Name:="TradeStatus")>
Public Enum TradeStatus

    NewOrder = 100
    SendToProvider = 101
    ProviderSubmitted = 102
    ProviderAccepted = 103
    ExecutionPending = 104
    Executed = 105
    TicketsCreated = 106 'TERMINAL STATE

End Enum

<DataContract(Namespace:="http://schema.aam.us.com/2010/6", Name:="StatusUpdate")> _
Public Class StatusUpdate

    Public Sub New(ByVal tradeStatus As TradeStatus, ByVal additionalInformation As String)
        Me.TradeStatus = tradeStatus
        Me.AdditionalInforamtion = additionalInformation
    End Sub

    <DataMember(IsRequired:=True)> _
    Public Property AdditionalInforamtion() As String

    <DataMember(IsRequired:=True)> _
    Public Property TradeStatus() As TradeStatus
End Class

生成的代码

<System.Diagnostics.DebuggerStepThroughAttribute(),  _
 System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0"),  _
 System.Runtime.Serialization.DataContractAttribute(Name:="StatusUpdate", [Namespace]:="http://schema.aam.us.com/2010/6"),  _
 System.SerializableAttribute()>  _
Partial Public Class StatusUpdate
    Inherits Object
    Implements System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged

    <System.NonSerializedAttribute()>  _
    Private extensionDataField As System.Runtime.Serialization.ExtensionDataObject

    Private AdditionalInforamtionField As String

    Private TradeStatusField As String

    <Global.System.ComponentModel.BrowsableAttribute(false)>  _
    Public Property ExtensionData() As System.Runtime.Serialization.ExtensionDataObject Implements System.Runtime.Serialization.IExtensibleDataObject.ExtensionData
        Get
            Return Me.extensionDataField
        End Get
        Set
            Me.extensionDataField = value
        End Set
    End Property

    <System.Runtime.Serialization.DataMemberAttribute(IsRequired:=true)>  _
    Public Property AdditionalInforamtion() As String
        Get
            Return Me.AdditionalInforamtionField
        End Get
        Set
            If (Object.ReferenceEquals(Me.AdditionalInforamtionField, value) <> true) Then
                Me.AdditionalInforamtionField = value
                Me.RaisePropertyChanged("AdditionalInforamtion")
            End If
        End Set
    End Property

    <System.Runtime.Serialization.DataMemberAttribute(IsRequired:=true, EmitDefaultValue:=false)>  _
    Public Property TradeStatus() As String
        Get
            Return Me.TradeStatusField
        End Get
        Set
            If (Object.ReferenceEquals(Me.TradeStatusField, value) <> true) Then
                Me.TradeStatusField = value
                Me.RaisePropertyChanged("TradeStatus")
            End If
        End Set
    End Property

    Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Protected Sub RaisePropertyChanged(ByVal propertyName As String)
        Dim propertyChanged As System.ComponentModel.PropertyChangedEventHandler = Me.PropertyChangedEvent
        If (Not (propertyChanged) Is Nothing) Then
            propertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
        End If
    End Sub
End Class

4 个答案:

答案 0 :(得分:18)

默认情况下序列化枚举。与primites和Collection类一样,您不需要使用[DataContract]标记它们。但是,这并不意味着WCF不允许您自定义序列化行为,因此本着互操作性的精神,您可以更改枚举的序列化方式。作为可自定义的一部分,如果使用DataContract标记它但不标记EnumMembers,则表示您正在更改默认序列化方案。在此处查看有关枚举序列化的更多信息Enum Serialization

编辑:我想更多地考虑这个问题,现在我开始想知道根本原因......结果证明这是WSDL的错。

默认情况下,如果不放置[DataContract],则默认情况下WCF将枚举序列化为具有[DataContract]和[EnumMembers]属性。所以如果你采取以下例子

[DataContract]
public enum FileType {
    [EnumMember]
    Text,
    [EnumMember]
    Pdf,
    [EnumMember]
    Word
}

它将生成以下WSDL

<xs:simpleType name="FileType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="Text" /> 
    <xs:enumeration value="Pdf" /> 
    <xs:enumeration value="Word" /> 
  </xs:restriction>
</xs:simpleType>
<xs:element name="FileType" nillable="true" type="tns:FileType" />

所以现在如果你拿出[EnumMember]这样的属性

[DataContract]
public enum FileType {
    Text,
    Pdf,
    Word
}

您的WSDL将如下所示:

<xs:simpleType name="FileType">
  <xs:restriction base="xs:string" /> 
</xs:simpleType>
<xs:element name="FileType" nillable="true" type="tns:FileType" />

所以第二个看起来就像第一个,除了没有枚举元素。现在第二个和描述简单字符串的WSDL有什么区别?没有。这就是为什么WCF代理生成一个字符串而不是枚举。

答案 1 :(得分:2)

简单 - 这就是它的工作方式。

在名称/值对的意义上,XML Schema没有枚举的概念。它最接近的是能够指示特定的简单类型可能具有多个值中的一个 - 在这种情况下为字符串值。

请注意,ASMX Web服务和XML Serializer完全相同。


好的,乔纳森和我都是对的,都是错的。

在序列化枚举时,WCF会将特定于.NET的信息添加到XML架构中。这允许另一个.NET实现将枚举视为枚举,并保留枚举值。

但是,没有其他平台能够理解这些信息。因此,枚举将被简单地视为一个字符串,只能取几个值中的一个。

答案 2 :(得分:1)

如果您包含DataContract属性,则需要使用EnumMember属性标记至少一个值。否则它无法看到任何值并将整个字段转换为字符串。

如果您不包含DataContract属性,则您也不需要EnumMember属性。

编辑:正确代码示例

<DataContract(Namespace:="http://schema.aam.us.com/2010/6", Name:="TradeStatus")> 
Public Enum TradeStatus 

    <EnumMember> NewOrder = 100 
    <EnumMember> SendToProvider = 101 
    <EnumMember> ProviderSubmitted = 102 
    <EnumMember> ProviderAccepted = 103 
    <EnumMember> ExecutionPending = 104 
    <EnumMember> Executed = 105 
    <EnumMember> TicketsCreated = 106 'TERMINAL STATE 

End Enum 

答案 3 :(得分:1)

因为该特定值有一个已定义的名称。

当给定值没有定义的名称时,序列化程序将写出一个整数,反序列化器将读取它就好了:

TradeStatus didntMakeCompileCutoffDate = (TradeStatus)dbRecord.TS; // value 999

如果序列化程序允许选择将特定枚举字段写为整数,那将是很好的,因为这将允许有效枚举名称列表增加而无需重新编译反序列化器代码。目前,由于无法识别的枚举名称,反序列化器将抛出异常(并拒绝整个合同)。

可以通过使用[EnumMember(Value =“123”)]解决此问题,并为编译时已知的每个枚举名称指定等效整数。来自MSDN Enumeration Types in Data Contracts

第二个解决方法是将合约枚举指定为使用整数后备存储并序列化后备存储的属性。 SO Link