David Foderick's Blog - OnMaterialize()

March 2007 - Posts

Debugging WCF Serialization issues

When serializing objects over WCF you might encounter the following not-so-helpful message.

System.ServiceModel.CommunicationException : The underlying connection was closed: The connection was closed unexpectedly.

And the Close method of your service proxy may complain that

System.ServiceModel.Security.MessageSecurityException : An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.

Which seems to indicate that there is a security exception. However, in my experience, the root problem has usually been a serialization issue.

To debug server-side issues, use a combination of the SvcTraceViewer.exe, an indispensible tool for debugging and tracing WCF messages, and simple tracing into the server-side code by attaching to the server process.

If indeed you have a serialization issue, you will be able to step through the Service method and the Server stack trace will end right at the point where you return from the service method.

Server stack trace:
   at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
...

However, at no point do you actually see the true source of the exception. It seems to get eaten somewhere in the channel. The best way that I have discovered to track down any serialization issues is to write unit tests that manually serialize the objects that pass through the WCF service. My serialization helper is a generic method like this:

        public static void LogDTO<TDTO>(TDTO dto)
        {
            DataContractSerializer ser =
                new DataContractSerializer(typeof(TDTO));
            FileStream writer = new FileStream(@"C:\log\"+dto.GetType().Name+".xml", FileMode.Create);
            ser.WriteObject(writer, dto);
            writer.Close();
        }
 

The unit test simply calls the LogDTO method for each serializable object.

Serializer.LogDTO<myDTO>(myDTOInstance);

And now you can resolve any serialization issues with an appropriate stack trace and exception message.

Posted: Mar 12 2007, 07:50 PM by admin | with 4 comment(s) |
Filed under:
Don't serialize your delegates!

This point is pretty obvious: when serializing objects in order to pass them through a service boundry, you should not bother to serialize the delegates. Since a delegate is a pointer to some method on some object in your memory space, that target object that the delegate points to probably doesn't exist in the memory space of the other machine! You will encounter this scenario if you create custom events on your business objects and then serialize them through WCF. Remember that a .NET event is just a list of delegates (commonly called the event's invocation list).

There are two issues that make this problem particularly onerous. First, if there are no subscribers to the event, the serialization works just fine! So your unit tests may work perfect - unless you are the one anal fool that unit tests subscribing to events and serializing those objects. Second, back in the UI, it may not be your code - it may be framework code - that is subscribing to these events and you will only get the SerializationException after you have databound the objects to UI controls and then try to serialize the databound objects. This will happen if for some crazy reason you want to implement INotifyPropertyChanged on your business entities.

Fortunately, the problem is pretty obvious when you encounter it. The excetpion message you get in the .NET 3.0 DataContractSerializer is :

"Type 'System.DelegateSerializationHolder+DelegateEntry' with data contract name 'DelegateSerializationHolder.DelegateEntry:http://schemas.datacontract.org/2004/07/System' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer."

Forget .NET's advice. The way to fix it simple. Just mark your event as NonSerialized.

[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;

The bottom line rule is to always mark events with the [field:NonSerialized] attribute on classes whose objects will be serialized accross a service boundry.

Reference: Do not serialize delegates and events blindly.