XmlSerializerFormat plus Huge Schema equals Trouble
Today I was taught an immensely important lesson by WCF. It actually has nothing to do with WCF except that because of the size of the schema I'm working with that is where I encountered it.
I do a lot of work in the healthcare industry, and that industry, by government mandate, works with a message format called the 837 (properly the X12 4010A1 837 either I, P or D). The 837 has three flavors, and is absolutely huge. I was crafting a service which had to accept an XML representation of this data. How did I create the XML? BizTalk Server 2006 R2's new HIPAA support of course. When I made the call to service from my unit tests I first received a Fault indicating that exception details could not be returned because of configuration. No problem, obviously I've seen this before and so I added the following to my app.Config for the Host executable:
Now that I've enabled debugging, surely now I'll see some sort of clear reason by this occurred. Nope! I was presented with the following:
TheCompany.Services.Tests.ClaimsService.GetListOfClaimsByStatus : System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail] : Error in deserializing body of request message for operation 'GetClaimListByStatus'.
Well isn't that terribly useful. Fortunately, this did give me the single most important piece of information "deserializing". So off I go to Google my brain, because I'd written a post before on how to debug the XmlSerializer (and I was using the XmlSerializer in this case because the DataContractSerializer could not work with my schema). As that post will tell you, there is a switch that can be set in the app.Config which will enable you to debug the code generated by the XmlSerializer. So now we add the following to my app.Config:
And we follow that by running the unit tests again, that results in something that is actively useful:
For those reading along at home and wanting the full text that says:
The maximum nametable character count quota (10000) has been exceeded while reading XML data. The nametable is a data structure used to store strings encountered during XML processing - long XML documents with non-repeating element names, attribute names and attribute values may trigger this quota. This quota may be increased by changing the MaxNameTableCharCount property on the XmlDictionaryReaderQuotas object used when creating the XML reader.
Now that is useful, it tells me exactly how to correct the problem and the size of the quota currently. The only problem is that I didn't create this XmlReader object, I didn't even create the XmlSerializer which created this XmlReader. The only thing which I create was a ServiceHost, how can I change that setting? Enter Google again.
As it happens, Windows Communication Foundation does include an ability to override that value, it is stored in the Binding Configuration in your ... you guessed it ... app.Config! Add the following snippet (assuming you're using Basic Http Binding (it exists for all bindings though) and you'll be good to go:
Now, surely I'm done, and things will work. Actually, no it took me a few times to find a value that would work for that quota. Once I did though I finally hit my breakpoint inside the service and was able to send back a response, where upon I got this message:
TheCompany.Services.Tests.ClaimsService.GetListOfClaimsByStatus : System.ServiceModel.CommunicationException : Error in deserializing body of reply message for operation 'GetClaimListByStatus'.
----> System.InvalidOperationException : There is an error in XML document (1, 252).
----> System.Xml.XmlException : The maximum nametable character count quota (10000) has been exceeded while reading XML data. The nametable is a data structure used to store strings encountered during XML processing - long XML documents with non-repeating element names, attribute names and attribute values may trigger this quota. This quota may be increased by changing the MaxNameTableCharCount property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 1, position 252.
At least when the error occurs on the client side you get the full details to start with! Make the same modification above to your configuration on the client side and you're good to go.