Catching streaming exceptions with streaming readers
About two years ago, I put up a post discussing how exceptions are streamed in WCF Data Services (called ADO.NET Data Services at the time).
Today I want to continue from yesterday's post and discuss how the client implements support for this, but first a quick note.
I'd like to make sure I clarify what I mean by a "streaming server", a "streaming client", and a "streamer reader". In all cases, the idea is the same: a component doesn't need to have all data at hand to do its work - it can work as long as it has enough to make some meaningful progress.
So the server doesn't need to hold all the query results in memory before writing them out: it can start writing them out as data comes from the database. The client doesn't need to read the complete payload before processing begins: it can start materializing objects as soon as there's enough information from the network. An XmlReader component is a streaming component because it doesn't need the complete document - just enough to provide all the right information after a .Read() method call.
As we know, when the server sends the response headers indicating success and it hits an error while sending the results, it will put the error information on the response and then terminate the connection without correctly closing out the rest of the document. This sends a very clear signal to non-streaming components that try to read the response, as it will fail to load in an implementation that checks for correct XML.
In the client library case, we not only want to avoid having to read the whole response before processing, but we also want to parse that last bit of XML with the error information.
Enter then the XmlAtomErrorReader, which wraps an existing XmlReader and checks at every step of the way whether an error is found, and if so deserializes that information and throws the exception. Internally, this makes things very nice for the library, because it can simply wrap the network reader with this one and forget about checking for errors - malformed XML errors, network errors or data service errors are handled the same way. Also, if we create a reader from some other structure like an XElement, we don't need the wrapping - the content will never have a streaming error.
If you look at the implementation, you'll find that it's very forgiving of foreign elements, and picks a single error message to propagate up. In a debugging scenario, you'll need some other tool if the server sends along additional custom fields, for example. You'll also note that the error message can be intermixed with comments, for example, but not other elements, so an HTML-based error message won't be supported.
Enjoy!
2015-07-02 update: XmlAtomErrorReader is no longer on CodePlex and instead can be found in the Reference Source for .NET Framework over here.