By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,920 Members | 1,660 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,920 IT Pros & Developers. It's quick & easy.

deserialization arrays in Axis SOAP messages

P: n/a
Summary:
I have been trying to make requests of a web service provided by Axis using
a dotnet client with code generated by wsdl.exe and have
been getting exceptions when trying to process the response.

As a result of seraching news groups I guessed that the SOAP response
defines an array element in a way that causes the dotnet deserialization
routines to put the content in a generic object array (object[]) BUT the
content is supposed to go into a specific array (e.g. paymentItem[]). As a
result, when the application tries to populate the reponse object, it tries
to assign the contents of an object[] into a paymentItem[] and things go
wonky.

I used SOAP extensions to manipulate the offending item in the SOAP
response, prior to deserialization, and the exceptions went away.

But, this solution is neither elegant nor suitable as a general means of
dealing with responses from Axis servers.

So, I'm looking for a better way to create dotnet web service clients that
must deal with Axis webservers.

Any body have any suggetions?
Here's the details of my problem and how I dealt with it:

Please note that I have almost no experience with SOAP and my terminology
may be weak.

I am trying to use a webservice from an Axis server. I was given a WSDL file
(I'm sorry, but as far as I know the file is not publicy available and as
such I haven't included it. I have asked if I can post its contents and may
be able to, at a later date, if required. I think I provide enough detail
below that the contents of the WSDL will not be required in order to solve my
problem). I used wsdl.exe to generate a c# file and used that code to make
requests of the Axis server.

I had the following exception when processing the SOAP response:
System.InvalidOperationException: There is an error in XML document (12,
19). ---> System.InvalidCastException: Cannot assign object of type
System.Object[] to an object of type
customertransactions.[editted].PaymentItem[].
at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlS erializationReader1.Read3_ResponseModel()
at
System.Xml.Serialization.XmlSerializationReader.Re adReferencingElement(String
name, String ns, Boolean elementCanBeType, String& fixupReference)
at System.Xml.Serialization.XmlSerializationReader.Re adReferencedElements()
at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlS erializationReader1.Read6_walletPaymentResponse()
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Deserialize (XmlReader
xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize (XmlReader
xmlReader, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize (XmlReader xmlReader)
at
System.Web.Services.Protocols.SoapHttpClientProtoc ol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtoc ol.Invoke(String
methodName, Object[] parameters)
at
.... [I removed the top level of the trace and made another small edit to the
exception text for proprietary reasons]

I have seen someone with a similar problem (It also appears that they were
trying to access the same web service) but the discussion seems to have ended
before a solution was posted (see
http://groups.google.com/groups?hl=e...TNGP10.phx.gbl)

I also found discussions, in what appear to be Axis user and developer mail
archives, about Axis/dotnet interop issues with respect to arrays
( see
http://www.mail-archive.com/ax******.../msg00629.html,
http://www.mail-archive.com/ax******.../msg23304.html,
and
http://www.mail-archive.com/ax******.../msg00195.html)

The latter mention how a SOAP message element may face deserialization
issues if the xsi:type attribute is "soapenc:Array" and the soapenc:arrayType
attribute is "xsd:anyType[n]" (where n is the number of elements in the
array). It specifically mentions that the contents may get put into an
object[].

As a result I tried to find a way to look at the SOAP requests and
responses. I found a reference to soapextensions (the reference was rather
sparse) and from there a found a link to a microsoft help page
(ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/cpguide/html/cpconalteringsoapmessageusingsoapextensions.htm#cp conalteringsoapmessageusingsoapextensionsanchor1)
that ALMOST exlplains how to create a soap extension that will log SOAP
messages. With some twiddling I got the logger to work.

The logged SOAP response was using anyType[n] to describe the array.
I did a test. I modified the SOAP response prior to deserialization by
replacing the anyType[n] text with a reference to the proper element type.
I did this by taking the logger example mentioned in the above link, and
just prior to calling the logger, I inserted the following (yes it's ugly, it
is test code):

if (!(message is SoapServerMessage))
{
TextReader reader = new StreamReader(oldStream);
string joe = reader.ReadToEnd();
int bbdd = joe.IndexOf("anyType");
StringBuilder xformHtml = new StringBuilder();

int pos1 = joe.IndexOf("xsd:anyType");
int pos2 = joe.IndexOf("[",pos1);
xformHtml.Append(joe.Substring(0,pos1));
xformHtml.Append("ns2:PaymentItem");
xformHtml.Append(joe.Substring(pos2));
joe = xformHtml.ToString();

Stream bbbb = new MemoryStream(System.Text.UTF8Encoding.UTF8.GetByte s(joe));
oldStream = bbbb;
}

When the response was modified by the above code, the deserialization did
not result in any exceptions and the resulting response object contained the
correct information.

Here's the orginial response (with the domain name of the service provider
changed):
<multiRef id="id0" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:ResponseModel"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns2="http://serviceprovider.com">
<message xsi:type="xsd:string">Stuff</message>
<paymentItems xsi:type="soapenc:Array" soapenc:arrayType="xsd:anyType[2]"">
<item href="#id1"/>
<item href="#id2"/>
</paymentItems>
<statusCode xsi:type="xsd:string">000</statusCode>
<transactionId xsi:type="xsd:string">1</transactionId>
</multiRef>
<multiRef id="id1" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns3:PaymentItem" xmlns:ns3="http://serviceprovider.com"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<amount xsi:type="xsd:string">415</amount>
<itemType xsi:type="xsd:string">CC</itemType>
</multiRef>
<multiRef id="id2" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns4:PaymentItem" xmlns:ns4="http://serviceprovider.com"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<amount xsi:type="xsd:string">0</amount>
<itemType xsi:type="xsd:string">CHARGES</itemType>
</multiRef>

The modified response only differed the in soapence:arrayType attribute of
the paymentItems element:
<paymentItems xsi:type="soapenc:Array"
soapenc:arrayType="ns2:PaymentItem[2]">

I noticed that the array elements were defined as PaymentItem.
It appears that the dotnet deserializion algorithms were not able to determine
that paymentItems was an array of PaymentItem elements unless the
soapenc:arrayType attribute was modified to explicity instruct so. This is
consistent with what I read in
http://www.mail-archive.com/ax******.../msg00195.html.

Now, I have found a way to get dotnet to process a specific SOAP message.
But it is ugly and it involves my having a knowledge of the SOAP message
contents and schema. From what little I know about web services they are
supposed to remove me from the loop and they are supposed to be platform
independent; given a wsdl file and a proper wsdl processor the client
developer doesn't need to know about the message content. So, I figure there
must be a better way to do this.

So, is there a known problem with Axis/dotnet interop with respect to
complex message objects (or, specifically, arrays) and is there a known
solution? Is there something that I must do if I know that I am using a
dotnet client to access an Axis webservice?

Please note that I have no control over the service provider. If the
solution involves client side changes, great. If it involves server side
changes, I'd like references that I can use to convince the service provider
that they need to address this issue, given that they want to deal with
dotnet clients.
Thanks
Nov 21 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
A follow up to the above.

I have created a work around that is better than manipulating the SOAP
message prior to deserialization.
Instead I have modified the class definitions that were generated by wsdl.exe.
The class definition now matches the type definitions of the objects
deserialized from the message.

Like so
The wsdl generated classes were (with element names changed, only the schema
is relevent):
public class Response {
public string message;
public Itemstuff[] Items;
public string status;
public string Id;
}

public class Itemstuff {
public string amount;
public string cur;
public string Type;
}

But the deserialized content treated Items as an object[], so I modified
Response like so:
public class Response {
public string message;
public object[] Items;
public string status;
public string Id;
}

And the problem went away.

That's great for this particular problem, but it means that I have to edit
wsdl.exe output in order to use an Axis web service.
My modifications may (I don't know) only work for this particular SOAP
message and may not work if I try to access the same web service from a
different type of web server.

So is there a general solution?
Is anyone aware of this issue and if so is it an Axis issue, a dotnet issue,
an interop issue or a result of SOAP schema ambiguities?
Nov 21 '05 #2

P: n/a
> Is anyone aware of this issue and if so is it an Axis issue, a dotnet
issue,
an interop issue or a result of SOAP schema ambiguities?
It results from ambiguities and impracticalities in the SOAP specifications.

The web service you are trying to access is using SOAP section-5 encoding.
How do I know this? It is the (use="encoded") in the WSDL.

But SOAP section-5 encoding is specifically dis-allowed by WS-I for
interoperability reasons:
http://www.ws-i.org/Profiles/BasicPr...nement16638080

[WS-I was formed to resolve some of the ambiguities and overlaps in the
various SOAP-relevant specs ]

For some history on SOAP Section-5 encoding versus literal encoding, see:
http://msdn.microsoft.com/msdnmag/is...s/default.aspx

IBM also agrees that doc/lit is the best approach:
http://www-106.ibm.com/developerwork.../ws-whichwsdl/
So, the short answer to your problem is: use document/literal web services.
This requires a change on the server (AXIS) side. I don't know if that is
possible in your case. If not, you have your workaround.

Also : Where does this WSDL come from ? Where do you get this webservice?
Is it a sample shipped with AXIS or something? Can we get the example
fixed?

-Dino

--
Dino Chiesa
Microsoft Developer Division
d i n o c h @ OmitThis . m i c r o s o f t . c o m

"parrot toes" <parrottoes@_WILL_NOT_RESPOND_hotmail.com.(donotsp am)> wrote
in message news:20**********************************@microsof t.com...A follow up to the above.

I have created a work around that is better than manipulating the SOAP
message prior to deserialization.
Instead I have modified the class definitions that were generated by
wsdl.exe.
The class definition now matches the type definitions of the objects
deserialized from the message.

Like so
The wsdl generated classes were (with element names changed, only the
schema
is relevent):
public class Response {
public string message;
public Itemstuff[] Items;
public string status;
public string Id;
}

public class Itemstuff {
public string amount;
public string cur;
public string Type;
}

But the deserialized content treated Items as an object[], so I modified
Response like so:
public class Response {
public string message;
public object[] Items;
public string status;
public string Id;
}

And the problem went away.

That's great for this particular problem, but it means that I have to edit
wsdl.exe output in order to use an Axis web service.
My modifications may (I don't know) only work for this particular SOAP
message and may not work if I try to access the same web service from a
different type of web server.

So is there a general solution?
Is anyone aware of this issue and if so is it an Axis issue, a dotnet
issue,
an interop issue or a result of SOAP schema ambiguities?

Nov 21 '05 #3

P: n/a
Sorry about the delay.

1) The WSDL provider has since changed their WSDL. It still has the
use=encoded attribute in the wsdlsoap:body elements (I assume that is the
element you referred to).
2) They don't publish their WSDL; they only provide it to registered
clients. As such, I'm not sure if they want me to redistribute it nor pass on
information about them. I have asked for permission to do so but have not
received a response.

Like you said, I've got my workaround.
I will forward the information you provided and maybe they will update their
site.

It's good to see IBM and Microsoft agreeing on stuff.

Thanks for your help.
"Dino Chiesa [Microsoft]" wrote:
Is anyone aware of this issue and if so is it an Axis issue, a dotnet
issue,
an interop issue or a result of SOAP schema ambiguities?


It results from ambiguities and impracticalities in the SOAP specifications.

The web service you are trying to access is using SOAP section-5 encoding.
How do I know this? It is the (use="encoded") in the WSDL.

But SOAP section-5 encoding is specifically dis-allowed by WS-I for
interoperability reasons:
http://www.ws-i.org/Profiles/BasicPr...nement16638080

[WS-I was formed to resolve some of the ambiguities and overlaps in the
various SOAP-relevant specs ]

For some history on SOAP Section-5 encoding versus literal encoding, see:
http://msdn.microsoft.com/msdnmag/is...s/default.aspx

IBM also agrees that doc/lit is the best approach:
http://www-106.ibm.com/developerwork.../ws-whichwsdl/
So, the short answer to your problem is: use document/literal web services.
This requires a change on the server (AXIS) side. I don't know if that is
possible in your case. If not, you have your workaround.

Also : Where does this WSDL come from ? Where do you get this webservice?
Is it a sample shipped with AXIS or something? Can we get the example
fixed?

-Dino

--
Dino Chiesa
Microsoft Developer Division
d i n o c h @ OmitThis . m i c r o s o f t . c o m

"parrot toes" <parrottoes@_WILL_NOT_RESPOND_hotmail.com.(donotsp am)> wrote
in message news:20**********************************@microsof t.com...
A follow up to the above.

I have created a work around that is better than manipulating the SOAP
message prior to deserialization.
Instead I have modified the class definitions that were generated by
wsdl.exe.
The class definition now matches the type definitions of the objects
deserialized from the message.

Like so
The wsdl generated classes were (with element names changed, only the
schema
is relevent):
public class Response {
public string message;
public Itemstuff[] Items;
public string status;
public string Id;
}

public class Itemstuff {
public string amount;
public string cur;
public string Type;
}

But the deserialized content treated Items as an object[], so I modified
Response like so:
public class Response {
public string message;
public object[] Items;
public string status;
public string Id;
}

And the problem went away.

That's great for this particular problem, but it means that I have to edit
wsdl.exe output in order to use an Axis web service.
My modifications may (I don't know) only work for this particular SOAP
message and may not work if I try to access the same web service from a
different type of web server.

So is there a general solution?
Is anyone aware of this issue and if so is it an Axis issue, a dotnet
issue,
an interop issue or a result of SOAP schema ambiguities?


Nov 23 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.