tags:

views:

80

answers:

3

Code on the server

<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

Generated code

<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
A: 

Simple - this is the way it's meant to work.

XML Schema has no concept of an enum, in the sense of a name/value pair. The closest it has is the ability to indicate that a particular simple type may have one of several values - string values in this case.

Note that ASMX web services and the XML Serializer do exactly the same thing.


OK, Jonathan and I are both right and both wrong.

When serializing an enum, WCF adds .NET-specific information to the XML Schema. This permits another .NET implementation to treat the enum as an enum, complete with preservation of the enum values.

However, no other platform is going to understand this information. As a result, an enum will simply be treated as a string which can only take on one of several values.

John Saunders
@Downvoter: what's the problem with this answer?
John Saunders
It wasn't even close to being right. By default WCF does serialize enumerations as enumerations. It is only if you include the DataContract attribute without using the EnumMember attribute that you get this behavior.
Jonathan Allen
@Jonathan: sorry, that's nonsense. Are you suggesting that it preserves the integer values? Take a look at the XML, and you'll see that an enumeration is serialized as the string value of the name of the enumeration, or the string specified in `EnumMember` if specified.
John Saunders
A: 

If you include the DataContract attribute, then you need to tag at least one value with the EnumMember attribute. Otherwise it can't see any of the values and turns the whole field into a string.

If you do not include the DataContract attribute, then you don't need the EnumMember attribute either.

EDIT: Example of correct code

<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 
Jonathan Allen
@Jonathan: why is this an answer and not an update to your question? Also, what are you referring to? Nobody mentioned `EnumMember`.
John Saunders
@Jonathan: also, are you suggesting that these integer values will appear in the service reference when consumed by a .NET client? Why not try that and post the results?
John Saunders
+1  A: 

Enums are serialized by default. Like primites and Collection classes you do not need to mark them with [DataContract]. However, that does not mean that WCF does not let you customize the serialization behavior, so in the spirit of interoperability you can change how the enum will be serialized. As part of that customizability if you mark it with DataContract but do not mark EnumMembers you are changing the default serialization scheme. See more on Enum serialization here Enum Serialization

EDIT: Got to thinking a bit more about this and now I started wondering about the underlying cause... turns out it is the WSDL's fault.

By default if you don't put [DataContract] then WCF by default serializes the enum as if it had the [DataContract] and [EnumMembers] attribute. So if you take the following example

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

it will generate the following 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" />

So now if you take out the [EnumMember] attributes like so

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

your WSDL will look like this:

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

So the second one looks just like the first one except without the enumeration elements. Now what is the difference between the second one and just a WSDL describing a simple string? None. That is why the WCF Proxy gen gives you a string instead of the Enum.

Johnathan, how is AAM treating you by the way? :) (John)

Mogounus