473,387 Members | 1,295 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

deserialization arrays in Axis SOAP messages

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
3 9754
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
> 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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: milkyway | last post by:
Hello all, I am new to the Axis world. I was just trying to understand something. Basically, Apache Axis will allow one to put web services on the Apache server? I am running apache2. Is there a...
3
by: Brad King | last post by:
I'm calling an Axis web service (from a .Net client) that returns an array of a complex type. The complex type wrapper appears to have been generated with all members intact from the wsdl using...
1
by: parrot toes | last post by:
I tried to post this question before, but there was an error when posting. I case it did get posted and in order to avoid duplication, I'll just repost a summary. I have written a dotnet client...
0
by: jennifer.perkins | last post by:
I've seen a couple posts by people having similar problems, but the suggested solutions I've tried so far haven't worked. I'm using a SOAP client in VB.Net (constructed by wsdl.exe) and the...
0
by: Jamie Phillips | last post by:
I'm sure this topic has been "around the block" a few times, but I have not been able to find ANY solutin that fits this particular problem. I have written a Java Axis web service that has a method...
7
by: Jamie Phillips | last post by:
I'm sure this topic has been "around the block" a few times, but I have not been able to find ANY solutin that fits this particular problem. I have written a Java Axis web service that has a method...
5
by: frustratedWithDotNet | last post by:
Why does .NET not issue messages or throw exceptions if it doesn't like something in the response from a web service?? I am getting a response object, but an array of custom objects within the...
3
by: Jeremy Chapman | last post by:
I've writtin a very simple web service in axis which returns an array of classes. I consume it in a .net app. When receiving the response, my .net app generates an error "Cannot assign object...
0
by: TraceyAnnison | last post by:
I wonder if you can help me - I'm new to this, and working in a project that has already been configured to work with Axis. We have a Java project built with the Spring framework, in order to...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.