I’ve finally learned my lesson about setting default values for C# Enumerates – always set them, because bad stuff happens when you don’t.
Our team built a web application that communicated with a business logic tier using WCF services. The design allowed us to utilize the same business and data retrieval logic across multiple client interfaces, returning Data Contracts to each interface, instead of scattering our logic enterprise-wide. Everything was working well… until we moved the application to Production.
After moving to Production, we began receiving an ugly, non-descript error message in our user interface that “an existing connection was forcibly closed by the remote host,” and we chased it for hours before we found the problem. First, we verified that we could communicate (authenticate and exchange information) with our WCF tier. Success. Next, we verified that our data schemas were the same in DEV and PROD. They were. Then, we checked for any problems with our user interface. None found. Finally, in a desperation move, I changed our database connection string to point to the development database server… and suddenly the application worked without errors… but re-pointing the connection string to production data caused the error to resurface. I was puzzled.
Finally, our first clue came to us when we checked the XML log file created by WCF. First, it logged a “Failed to send response message over HTTP” error, which was followed by an error message giving us the real error:
<Message>There was an error while trying to serialize parameter http://tempuri.org/:[WcfOperationContractName]. The InnerException message was 'Enum value '0' is invalid for type '[Client].[Application].Entity.[EnumerateType]' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.'. Please see InnerException for more details.< SPAN>Message>
It turns out that the stored procedure feeding data to this service returned some nullable columns of data, including the enumerate value, and this column happened to be NULL in Production but not in Development. So, when WCF attempted to serialize the Data Contract and deliver it to the interface, it failed. Unfortunately, the user interface did not receive a friendly message, but at least the information was in the WCF server logs.
In order to prevent this problem, I made two code modifications. First, I included an “Unknown” Enum Member in my enumerate with a numeric value of 0:
[
DataContract]
public enum SampleEnumerateType
{
[
EnumMember] Unknown = 0,
[
EnumMember] High = 1,
[
EnumMember] Medium = 2,
[
EnumMember] Low = 3
}
Next, I added a default value to the property where this enumerate was used:
private SampleEnumerateType _status = SampleEnumerateType.Unknown;
[
DataMember]
public SampleEnumerateType Status
{
get { return _status; }
set { _status = value; }
}
And with that, the problem vanished. Our user interface correctly displayed its data – including a row with a status value of “Unknown” – and the application was ready for primetime.
posted on Tuesday, September 11, 2007 12:48 PM