Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum Value Is Not Deserialized By WCF Service

Tags:

c#

wcf

I built a WCF service and there's a section that looks like this:

[ServiceContract]
public class Service {
    [OperationContract]
    public SomethingElse[] Method(Code a, params Something[] b) { ... }
}

[DataContract]
public class Something {
    [DataMember]
    public string Stuff {get;set;}
    [DataMember]
    public Status MyStatus {get;set;}
    public string ServerSideField {get;set;}
}

[DataContract]
public class SomethingElse {
    [DataMember]
    public Status MyStatus {get;set;}
}

[DataContract]
public enum Status {
    [EnumMember] WorksFine,
    [EnumMember] NotWorking
}

[DataContract]
public enum Code {
    [EnumMember] TypeA,
    [EnumMember] TypeB
}

Now I am using it as a service reference for a C# client. For some reason, whenever I call Method, the MyStatus property inside the b parameter is always set to WorksFine, even if I set it to NotWorking. On the other hand, whenever I pass Code.TypeA or Code.TypeB for the a argument, the service always deserializes it correctly.

For the sake of due diligence, other posts on the subject of passing enums to WCF services refer to DataContract, EnumMember(Value="TypeA"), and ServiceKnownType so I gave all of those a shot. However, even when I use ServiceKnownType (like below), I am still encountering the same problem.

[ServiceContract]
[ServiceKnownType(typeof(Something)]
[ServiceKnownType(typeof(Status)]
public class Service {
    [OperationContract]
    public SomethingElse[] Method(Code a, params Something[] b) { ... }
}

This issue seems unusually obscure for something so basic. I tested passing back Status.NotWorking from the service as well and the client is able to see it, so this appears to be a one-way issue. Any suggestions?

EDIT 1:

Similar issue: WCF not deserializing value types. Mysterious behaviour

EDIT 2:

Judging from the lack of immediate response, I am going to include some more information in case some of it sticks.

  • I'm experiencing this problem on both .NET 4.5 and 4.0.
  • The service is hosted on IIS, has SSL, and custom authentication scheme.
  • There is also a FaultContract attribute on Method but I excluded it to make the example simpler.
  • Event Viewer says zilch. So does IIS logs.
  • Auto-generated service reference code in Reference.cs looks like this:

The enum:

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.datacontract.org/2004/07/Service")]
public enum Status{ TypeA, TypeB }

The method:

// CODEGEN: Parameter 'MethodResult' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlArrayAttribute'.
    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/Service/Method", ReplyAction="http://tempuri.org/Service/MethodResponse")]
    [System.ServiceModel.FaultContractAttribute(typeof(MyClientProject.Service.MyFault), Action="http://tempuri.org/Service/MethodMyFaultFault", Name="MyFault", Namespace="http://schemas.datacontract.org/2004/07/Service.MyFault")]
    [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
    MyClientProject.Service.Method Method(MyClientProject.Service.MethodRequest request);

EDIT 3:

I built another web service consisting of just the code above, but it does NOT reproduce the behavior that I am seeing. My conjecture is that either some other code is zilching the DataContractSerializer, OR there is some relevant IIS/WCF setting, OR some unresolved data contract issues.

I also built another web client that connects to both webservices, and it is receiving the same results as the first.

EDIT 4

Intercepted request with Fiddler and it looked like this:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Method xmlns="http://tempuri.org/">
<a>TypeA</a>
<b><Something xmlns="http://schemas.datacontract.org/2004/07/TestService.Something">
   <Stuff>mystuffvalue</Stuff>
</Something></b>
</Method>
</s:Body>
</s:Envelope>

So the enum is never being passed after all! How do I fix this contract mismatch?

EDIT 5

Forgot to mention that the web service had a reference to an ASMX service and was itself using XML serializer to communicate with that external service.

like image 381
stephen Avatar asked Jan 28 '15 22:01

stephen


2 Answers

The key is here:

[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]

The XML Serializer is being used to generate the proxy instead of the DataContractSerializer. Did you accidentally specify the XmlSerializer? Are you trying to use an .asmx service?

Once you figure out what is causing the code to be generated using the XmlSerializer you'll have your answer, but it's not immediately evident from what you have posted.

like image 97
moarboilerplate Avatar answered Sep 29 '22 16:09

moarboilerplate


For some unknown reason, the SOAP request made by the client was omitting the enum values that I needed, and consequently the server serialized those enums to their default values (the first enum definition on the list).

I fixed this issue by making omitted parameters required for the request body. This is the code that fixed it:

[DataContract]
public class Something {
    [DataMember]
    public string Stuff {get;set;}
    [DataMember(IsRequired=true)] // just this 1 simple change!
    public Status MyStatus {get;set;}
    public string ServerSideField {get;set;}
}
like image 25
stephen Avatar answered Sep 29 '22 15:09

stephen