Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Solved: null responses with interop between Axis service and .NET client

8 views
Skip to first unread message

stacy_friedman

unread,
Mar 3, 2004, 1:46:27 PM3/3/04
to
Hi,

I was having a similar issue to several other posters here, namely
that when I called through to an Axis web service using a .NET client,
I'd get back null/false/zero-valued responses for any complex
datatypes. Here's the problem:

In Axis, the complex datatypes are auto-generated using WSDL2Java, as
is the rest of the service code. The code for a typical complex type
might look like this:

public class MyType implements java.io.Serializable {
private long field1;
private boolean field2;
...
static {
typeDesc.setXmlType(new
javax.xml.namespace.QName("urn:my.namespace", "MyType"));
org.apache.axis.description.ElementDesc elemField = new
org.apache.axis.description.ElementDesc();
elemField.setFieldName("field1");
elemField.setXmlName(new javax.xml.namespace.QName("",
"field1"));
elemField.setXmlType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema",
"long"));
typeDesc.addFieldDesc(elemField);
elemField = new org.apache.axis.description.ElementDesc();
elemField.setFieldName("field2");
elemField.setXmlName(new javax.xml.namespace.QName("",
"field2"));
elemField.setXmlType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema",
"boolean"));
typeDesc.addFieldDesc(elemField);
}

Look familiar? So a response from this Axis service that contained a
serialization of MyType would look like this:

<soapenv:Body>
<myMethodReturn xmlns="urn:my.namespace">
<field1 xmlns="">12345</field1>
<field2 xmlns="">true</field2>
</myMethodReturn>
</soapenv:Body>

If that also looks familiar, here's the problem: The namespace of the
interior fields in the complex type don't match the namespace of the
type itself, and .NET doesn't seem to like that.

There are two ways to solve this.

Method 1: Modify your Axis service

In the Axis service, add the appropriate namespace in the setXmlName
method:

[old]
elemField.setXmlName(new javax.xml.namespace.QName("",
"field1"));
[new]
elemField.setXmlName(new
javax.xml.namespace.QName("urn:my.namespace", "field1"));

Then the SOAP response looks like this:

<soapenv:Body>
<myMethodReturn xmlns="urn:my.namespace">
<field1>12345</field1>
<field2>true</field2>
</myMethodReturn>
</soapenv:Body>

And then .NET can deserialize it just fine.
Of course, this means you need to be able to change your Axis web
service code, or at least file a bug with your provider. If you
can't, the next solution also works:

Method 2: Tell .NET what to expect

After you point VS.NET at your Axis WSDL, you get your Web Reference.
You've probably already figured out that you need to modify your port
number in Reference.cs (I use C#) to connect properly, but you can
also modify the deserialization of the complex type to work properly
with what's on the wire already. Axis sends back a message that looks
like this:

<soapenv:Body>
<myMethodReturn xmlns="urn:my.namespace">
<field1 xmlns="">12345</field1>
<field2 xmlns="">true</field2>
</myMethodReturn>
</soapenv:Body>

But the default serialization in Reference.cs looks like this:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:my.namespace")]
public class MyType {

/// <remarks/>
public long field1;

/// <remarks/>
public bool field2;
}

In other words, .NET expects to find field1 and field2 in the same
namespace as the type itself, but Axis doesn't send that. To tell
.NET that the namespaces of the inner fields is "", make this change:

/// <remarks/>
[System.Xml.Serialization.XmlElement(Namespace="")]
public long field1;

/// <remarks/>
[System.Xml.Serialization.XmlElement(Namespace="")]
public bool field2;

That will get .NET to look for the fields in the right namespace, and
it will find them and deserialize them properly.

Hope this helps,

Stacy

scott

unread,
Mar 3, 2004, 2:06:07 PM3/3/04
to
Stacy,

I was almost going to say you are god. Anyway though I haven't tried your solution but I felt it is going to work with yours.

Thanks in advance,

Scott

Scott

unread,
Mar 4, 2004, 5:01:09 AM3/4/04
to
Thanks, Stacy.

Your post pointed me to the right direction. Though I did not have the problem you had with the namespace since my response was formed correctly by Axis:

<soapenv:Body><LoginResponse xmlns="urn:mynamespace"><response>Now this is really simple</response></LoginResponse></soapenv:Body>

the problem I had is with the reference classes which .NET generated:

/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("login", RequestElementName="loginRequest", RequestNamespace="urn:mynamespace", ResponseNamespace="urn:mynamespace", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("response")]

With your post I found that I needed to modify the method attribute as the following:

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("login", RequestElementName="loginRequest", ResponseElementName="LoginResponse", RequestNamespace="urn:mynamespace",

by adding a "ResponseElementName" to reflect the fact that element "response" is a child element of response element "LoginResponse". It worked with this change.

Hopefully the next .NET studio release would fix this problem.

By the way with attribute elementFormDefault="qualified" set in my schema header I was able to change from

<LoginResponse xmlns="urn:mynamespace"><response xmlns="">Now this is really simple</response></LoginResponse>

to

<LoginResponse xmlns="urn:mynamespace"><response>Now this is really simple</response></LoginResponse>

since they now are in one namespace.

Thanks again for sharing your solution.

Scott

0 new messages