by Jim
Dec 15, 2009 12:29 PM
We recently got bitten by a tricky bug in our web service (asmx.) One of the returned classes had a setter marked as internal, and the serialization failed for an HTTP Post request.
Now you’re thinking, “What’s tricky about that? XML serialization doesn’t work with readonly properties.”
But you would be wrong. The service passed all of our automated tests just fine. These were Visual Studio web tests, set up by default to send SOAP requests. When SOAP headers are sent, the SoapServerProtocol happily uses XMLSerializer to serialize the return value, complete with internal or private properties.
I’ll jump in here with the moral of the story: if you want to ensure that serialization will work regardless of how your service is called, then it should be tested with both SOAP and Post requests – or perhaps just Post, as this is the more restrictive.
Another option, if you aren't doing integration tests, is to add unit tests which simply serialize the service's arguments and return values. These should catch any new or changed properties which break serialization - assuming that they're kept up to date with the method signatures.
The explanation is more complicated. Two different ServerProtocol-derived classes handle these requests: HTTPServerProtocol and SOAPServerProtocol. They both use XMLSerializer.FromMappings() to create the XMLSerializer which handles the return value. This method is “not intended to be used directly from your code,” according to MSDN.
I attempted to use the Microsoft symbol server to step through the creation of the serializers, but it didn’t want to give me the appropriate web service classes. And .NET Reflector got tiring before I tracked down exactly what was going on. But somewhere in there is the capability to construct and use XMLSerializer in such a way as to serialize readonly properties – something that isn’t possible with the methods intended for public consumption.