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.
Method
but I excluded it to make the example simpler.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.
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.
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;}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With