Wednesday, February 15, 2012

WCF : error caused by a serialization issue

A colleague had an error cropping up when calling a WCF method that took a data contract as a parameter and returned a modified data contract. We couldn't quite pin-point or blame any code that we were looking at. The error was a standard WCF error message, along the lines of "The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.7490000'."
We had a schneaky suspicion that the error was not related to the timeout portion of the description, as the call was returning in under a second, let alone the 1 minute being reported.

Try as we may, logical (to us) debugging wasn't coming up with anything fruitful, so trial-and-error methods started taking place. Slowly, code started being commented out until the error stopped happening. The clincher ended up being when a data member in one of the data contracts was commented out. The code miraculously worked.

The property in question was an Enum, and what ended up being the problem was that the values in the enum were specified as 1 and 2. In the server side call, certain conditions caused a new object to be created, but the fact that the default value for the enum property was 0, we weren't setting it, and the enum only had values for 1 and 2, caused something to go wrong when the message was coming back. Changing the enum to start from 0 immediately solved the problem.

To confirm this behaviour, I made a separate project/solution to reproduce this; the results were as expected and mimicked the results we had seen earlier. What was interesting to me, though, was instantiating a new datacontract on the client/proxy side of the call, and passing it through as the parameter. I immediately got an exception with HELPFUL information this time round: "There was an error while trying to serialize parameter http://tempuri.org/:data. The InnerException message was 'Enum value '0' is invalid for type 'WCFServiceContracts.Gender' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.'".  If you'd like to see the entire project, you can grab it here
Here's a look at the contract/enum I used in reproducing the error. By instantiating a variable of type Person in the service call and not setting that value of Gender, the 1st error I mentioned gets thrown. Instantiating the same on the client, and passing it as a parameter causes the second to be thrown. Two ways of fixing it are (1) starting the enum at 0 or (2) setting the enum property in a constructor.


[DataContract]
public class Person
{
    [DataMember]
    public string FirstName { get; set; }
 
    [DataMember]
    public string LastName { get; set; }
 
    [DataMember]
    public Gender Gender { get; set; }
 
}
 
[DataContract]
public enum Gender
{
    [EnumMember]
    Male = 1,
    [EnumMember]
    Female = 2,
 
}
I understand that you don't want certain information to flow back to the client/caller for security reasons, but even after modifying the service behaviour to include exceptions details, I couldn't get the server to give me a meaningful message related to the serialisation problem

No comments:

Post a Comment