I am writing an application in Delphi 2007 which consumes a web service. I used the WSDL importer to generate the necessary code to communicate with the service, but I'm getting "unexpected subelement (elementname)" errors when trying to use the service.
Using Fiddler 2, I've found that the problem is that an xmlns is being added to an array of values sent in the SOAP message:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="..." xmlns:xsd="..." xmlns:xsi="...">
<SOAP-ENV:Body>
<Request xmlns="http://service.com/theService/">
<UserName xmlns="">user</UserName>
<Password xmlns="">pass</Password>
<List xmlns="">
<Item xmlns="http://service.com/theService/">123456</Item>
<Item xmlns="http://service.com/theService/">84547</Item>
</List>
</Request>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
If I resend the message created by Delphi in Fiddler, changing the xmlns for Item elements to an empty string, I no longer get an error, and the service responds properly. ie:
<List xmlns="">
<Item xmlns="">123456</Item>
<Item xmlns="">84547</Item>
</List>
Now, I am able to get rid of the xmlns attribute for list items by changing part of the initialization of my service class from:
InvRegistry.RegisterInvokeOptions(TypeInfo(ServicePort), ioDocument);
InvRegistry.RegisterInvokeOptions(TypeInfo(ServicePort), ioLiteral);
RemClassRegistry.RegisterSerializeOptions(RequestType, [xoLiteralParam]);
to:
InvRegistry.RegisterInvokeOptions(TypeInfo(ServicePort), ioDocument);
RemClassRegistry.RegisterSerializeOptions(RequestType, [xoHolderClass, xoLiteralParam]);
However, this will then cause the Request element name to be changed to the name of the default SOAP action (ex. GetInformation), which will again cause an error. I've been struggling with this for way too long, any ideas would be appreciated.
Also, I've created a test C# app which consumes the service, and it doesn't have any problems communicating with the service.
I've spoken with other people who have had similar problems with serialization in Delphi, and it seems that there is no clear-cut way to fix this issue.
Instead, the solution I've gone with is to attach an event handler to the OnBeforeExecute event of the THTTPRIO object that sends the SOAP message, which gives you access to the serialized soap message as a string. From there I just parsed out the attribute that was causing the problem, and now everything works.
A bit of an ugly solution, but it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With