понедельник, 8 ноября 2010 г.

QBFC: UTFDataFormatException exception workaround.

Steps to reproduce: application tries to perform simple QBFC query to QuickBooks 2010 on purpose of all customers retrieval using next code (creation of connection to QuickBooks is omitted for the sake of simplicity):
 

protected IMsgSetRequest _requests = _session.CreateMsgSetRequest("US", 7, 0);
...
_requests.ClearRequests();
ICustomerQuery customerQuery = _requests.AppendCustomerQueryRq();
String requestsXml = _requests.ToXMLString();
String responsesXml = RequestProcessor.ProcessRequest(Ticket, requestsXml);
_responses = ConversionHelper.ToMsgSetResponse(responsesXml, Session);


This code worked absolutely correctly for ages, but particular client faced with exception System.Runtime.InteropServices.COMException (0x80040301): An exception occurred! Type:UTFDataFormatException, Message:invalid byte 2 (M) of a 2-byte sequence.SAXParseException: error at line 82732, column 4 in XML data. which was thrown in the last line of the code snippet above. Firstly I thought that such exception can be related with QuickBooks company data corruption, but its verification and rebuilding neither revealed any inconsistencies nor eliminated mentioned issue. I tried to investigate content of responsesXml string, but it contained absolutely valid data. I tried to delete customer related with XML document line mentioned in the exception, but exception started to raise in other absolutely correct places. But finally I found workaround which didn't explain reasons of this issue, but at least helped to eliminate given exception. This workaround consists in addition of fake filter to the customer request before its performing. I used next variant:

customerQuery.ORCustomerListQuery.CustomerListFilter.FromModifiedDate.SetValue(DateTime.Parse("1/1/1971"), true);

As you probably know, TimeModified element of QuickBooks entity can't be less than 1/1/1971, so any data can't be filtered out using this expression. Final version of the code snippet looks like:

 
protected IMsgSetRequest _requests = _session.CreateMsgSetRequest("US", 7, 0);
...
_requests.ClearRequests();
ICustomerQuery customerQuery = _requests.AppendCustomerQueryRq();

customerQuery.ORCustomerListQuery.CustomerListFilter.FromModifiedDate.SetValue(DateTime.Parse("1/1/1971"), true);
String requestsXml = _requests.ToXMLString();
String responsesXml = RequestProcessor.ProcessRequest(Ticket, requestsXml);
_responses = ConversionHelper.ToMsgSetResponse(responsesXml, Session);


This code works absolutely correctly and returns all customers from the mentioned client's QuickBooks company.