Dino,
Yes I did search the axis-users group for days before I came to asking for
help in this group. For some reason the solution they provide there don't
work for me.
You are right that from axis server side, I need to hand craft the skeleton
codes/settings before I can use the session handler, and I did manage to
overcome the problem on that side.
Back to the issue here. I have been experimenting further, by modifying the
wsdl file namespace. Then, magically, the getSession() function call
succeeded. From that point view, the xsi:type may not be an issue.
But, problems are not finished yet, the subsequent call closeSession() from
the .bet client does not have the sessionID included in the header. This is
the .net->axis request for closeSession() after the getSession() call:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="
http://www.w3.org/2001/XMLSchema">
<soap:Body>
<closeSession xmlns="urn:myname.com" />
</soap:Body>
</soap:Envelope>
Any idea?
Here is the modified WSDL:
========================================
<?xml version="1.0" encoding="UTF-8" ?>
<wsdl:definitions targetNamespace="urn:myname.com"
xmlns="
http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="
http://xml.apache.org/xml-soap"
xmlns:impl="urn:myname.com"
xmlns:intf="urn:myname.com"
xmlns:soapenc="
http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="
http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="
http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="
http://www.w3.org/2001/XMLSchema"
xmlns:sens="
http://xml.apache.org/axis/session">
<wsdl:types>
<schema targetNamespace="urn:myname.com"
xmlns="
http://www.w3.org/2001/XMLSchema">
<element name="sessionID" type="impl:session" />
<complexType name="session">
<sequence>
<element minOccurs="1" maxOccurs="1" name="id" type="xsd:long" />
</sequence>
</complexType>
<element name="getSession">
<complexType>
<sequence>
<element name="username" type="xsd:string" />
<element name="password" type="xsd:string" />
</sequence>
</complexType>
</element>
<element name="getSessionResponse">
<complexType>
<sequence>
<element name="getSessionReturn" type="xsd:string"
form="qualified" />
</sequence>
</complexType>
</element>
<element name="closeSession">
<complexType />
</element>
<element name="closeSessionResponse">
<complexType />
</element>
</schema>
</wsdl:types>
<wsdl:message name="soapHeader">
<wsdl

art name="sessionID" element="impl:sessionID" />
</wsdl:message>
<wsdl:message name="getSessionRequest">
<wsdl

art element="impl:getSession" name="parameters" />
</wsdl:message>
<wsdl:message name="getSessionResponse">
<wsdl

art element="impl:getSessionResponse" name="parameters" />
</wsdl:message>
<wsdl:message name="closeSessionRequest">
<wsdl

art element="impl:closeSession" name="parameters" />
</wsdl:message>
<wsdl:message name="closeSessionResponse">
<wsdl

art element="impl:closeSessionResponse" name="parameters" />
</wsdl:message>
<wsdl

ortType name="MynameService">
<wsdl

peration name="getSession" parameterOrder="">
<wsdl:input message="impl:getSessionRequest"
name="getSessionRequest" />
<wsdl

utput message="impl:getSessionResponse"
name="getSessionResponse" />
</wsdl

peration>
<wsdl

peration name="closeSession">
<wsdl:input message="impl:closeSessionRequest"
name="closeSessionRequest" />
<wsdl

utput message="impl:closeSessionResponse"
name="closeSessionResponse" />
</wsdl

peration>
</wsdl

ortType>
<wsdl:binding name="MynameServiceSoapBinding" type="impl:MynameService">
<wsdlsoap:binding style="document"
transport="
http://schemas.xmlsoap.org/soap/http" />
<wsdl

peration name="getSession">
<wsdlsoap

peration soapAction="" />
<wsdl:input name="getSessionRequest">
<wsdlsoap:header message="impl:soapHeader" part="sessionID"
use="literal"/>
<wsdlsoap:body namespace="urn:myname.com" use="literal" />
</wsdl:input>
<wsdl

utput name="getSessionResponse">
<wsdlsoap:header message="impl:soapHeader" part="sessionID"
use="literal"/>
<wsdlsoap:body namespace="urn:myname.com" use="literal" />
</wsdl

utput>
</wsdl

peration>
<wsdl

peration name="closeSession">
<wsdlsoap

peration soapAction="" />
<wsdl:input name="closeSessionRequest">
<wsdlsoap:header message="impl:soapHeader" part="sessionID"
use="literal"/>
<wsdlsoap:body namespace="urn:myname.com" use="literal" />
</wsdl:input>
<wsdl

utput name="closeSessionResponse">
<wsdlsoap:header message="impl:soapHeader" part="sessionID"
use="literal"/>
<wsdlsoap:body namespace="urn:myname.com" use="literal" />
</wsdl

utput>
</wsdl

peration>
</wsdl:binding>
<wsdl:service name="MynameServiceService">
<wsdl

ort binding="impl:MynameServiceSoapBinding" name="MynameService">
<wsdlsoap:address
location="
http://localhost:8080/services/MynameService" />
</wsdl

ort>
</wsdl:service>
</wsdl:definitions>
====================================
This is the created client proxy:
namespace MyNameSpace{
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;
/// <remarks/>
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="MynameServiceSoapBindi
ng", Namespace="urn:myname.com")]
public class MynameServiceService :
System.Web.Services.Protocols.SoapHttpClientProtocol {
public session sessionID;
/// <remarks/>
public MynameServiceService() {
this.Url = "
http://localhost:8080/services/MynameService";
}
/// <remarks/>
[System.Web.Services.Protocols.SoapHeaderAttribute("sessionID",
Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("",
RequestNamespace="urn:myname.com", ResponseNamespace="urn:myname.com",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("getSessionReturn")]
public string
getSession([System.Xml.Serialization.XmlElementdttribute(Form=System.Xml.Sch
ema.XmlSchemaForm.Unqualified)] string username,
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSche
maForm.Unqualified)] string password) {
object[] results = this.Invoke("getSession", new object[] {
username,
password});
return ((string)(results[0]));
}
/// <remarks/>
public System.IAsyncResult BegingetSession(string username, string password,
System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("getSession", new object[] {
username,
password}, callback, asyncState);
}
/// <remarks/>
public string EndgetSession(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}
/// <remarks/>
[System.Web.Services.Protocols.SoapHeaderAttribute("sessionID",
Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("",
RequestNamespace="urn:myname.com", ResponseNamespace="urn:myname.com",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public void closeSession() {
this.Invoke("closeSession", new object[0]);
}
/// <remarks/>
public System.IAsyncResult BegincloseSession(System.AsyncCallback callback,
object asyncState) {
return this.BeginInvoke("closeSession", new object[0], callback,
asyncState);
}
/// <remarks/>
public void EndcloseSession(System.IAsyncResult asyncResult) {
this.EndInvoke(asyncResult);
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:myname.com")]
[System.Xml.Serialization.XmlRootAttribute("sessionID",
Namespace="urn:myname.com", IsNullable=false)]
public class session : System.Web.Services.Protocols.SoapHeader {
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSche
maForm.Unqualified)]
public long id;
}
}
Dino Chiesa said:
yes, I think you are correct. the xsi:type="xsd:long" seems to be
incorrect.
BUT!
We are changing the WSDL here without modifying the server. The WSDL
documents how we would like the service to appear, but if we design the WSDL
independently of the implementation of the service (in AXIS) , then
there
is
no way of knowing if the two independent things coincide.
It appears that AXIS is using doc/literal for the SOAP body and
soap-section-5 encoded for the SOAP header. Can you check this in the
server/service implementation?
--------------------
It seems like you may be using the AXIS SimpleSessionHandler ? If so,
there are others who have tried to get this to work and had troubles, for
example see the axis user mailing list archive, eg
http://marc.theaimsgroup.com/?l=axis-user&m=107694009529949&w=2
or
http://marc.theaimsgroup.com/?l=axis-user&m=104204463001241&w=2
or to search the archive:
http://marc.theaimsgroup.com/?l=axis-user&w=2&r=1&s=sessionhandler&q=b
The problem is that AXIS's WSDL2Java tool does not handle soapheaders as
defined in WSDL. If you have a WSDL (such as you have constructed here)
that specifies a soapheader to be used in the input message, the output
message, or both, then the Java implementation generated from AXIS'
"wsdl2java --server-side" does not have any support for that header. As a
developer using AXIS, you need to provide a handler to extract the header,
or insert the header, as appropriate.
The "SimpleSessionHandler" code included with AXIS v1.1 shows this. As you
can see, there is some DOM walking you have to do to extract the header and
de-marshal it and validate it and so on. I suppose there is similar work
you have to do to "add" the header to the response.
But even with all this I am not sure why the header would be section-5
encoded when the body is not. In the WSDL model, the soap body can in
fact be a different "use" than the header. In other words the literal or
section-5 encoded is specified on the body independently from the header.
Eg,
<wsdl

utput name="getSessionResponse">
<wsdlsoap:header message="impl:soapHeader" part="sessionID"
use="literal"/>
<wsdlsoap:body namespace="urn:myname.com" use="literal" />
</wsdl

utput>
-Dino
has
a
data type of long, instead of the earlier string[], and it has a sensible
name "id" that I set, instead of the earlier generated name of "Text" (these
are the only changes in the whole generated client proxy file):
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(Namespace="
http://xml.apache.org/
axis/session")]
[System.Xml.Serialization.XmlRootAttribute("sessionID",
Namespace="
http://xml.apache.org/axis/session", IsNullable=false)]
public class session : System.Web.Services.Protocols.SoapHeader {
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSche
maForm.Unqualified)]
public long id;
}
I have noticed that the "id" is unqulified, while in the example you showed
the "s" does not have the "Unqualified" attribute.
However, even with this change, I still got the same error of
InvalidOperationException. Since the wsdl file is manually edited, I did
not change Axis server side. For the session handling, I simply use
SimpleSessionHandler handler, a convenient handler that Axis provided.
I have also tested the code with the "Form = ... Unqualified" manually
removed from the generated proxy code, I still got the same error.
The
eror
message is copied here again for completeness:
=======================================
Unhandled Exception: System.InvalidOperationException: There is an
error
in
XML
document (4, 4). ---> System.InvalidOperationException: The specified type
was n
ot recognized: name='long',
namespace='
http://www.w3.org/2001/XMLSchema',
at
<se
ssionID xmlns='
http://xml.apache.org/axis/session'>.
at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read
1_session(Boolean isNullable, Boolean checkType)
at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read
8_OutHeaders()
=======================================
The returned SOAP message is
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="
http://www.w3.org/2001/XMLSchema"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<ns1:sessionID soapenv:mustUnderstand="0" xsi:type="xsd:long"
xmlns:ns1="
http://xml.apache.org/axis/session">-5227012230670020468</ns1:ses
sionID>
</soapenv:Header>
...
the position (4,4) indicated in the error message is the ns1:sessionID tag.
Does this message looks right to you, compared to what WSDL declared?
Somehow I felt the xsi:type="xsd:long" is not right, since dot/lit style
don't usually have this.
-Zihong
If I modify your WSDL to type the session ID this way:
<element name="sessionID" type="sess:session"/>
<complexType name="session">
<sequence>
<element minOccurs="1" maxOccurs="1" name="s"
type="xsd:long"/>
</sequence>
</complexType>
it works, and generates a header class like so:
public class session : System.Web.Services.Protocols.SoapHeader {
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute()]
public long s;
}
I think the problem is, in .NET the soapheader must derive from
System.Web.Services.Protocols.SoapHeader . In other words it is a
complexType. In your WSDL you have it as a simpleType. Generating a
client
proxy from that WSDL results in some confusion. Feels like a bug in the
wsdl.exe compiler.
The simple fix is to change the definition of the header type in XSD to
the
above. This generates what you would expect, I think.
But you have to ensure this synchronizes with the AXIS server. If
you
are
generating the server from the WSDL then it should be no problem .
-Dino
Dino,
Thanks. That works.
Now I have a second issue: the soap header. As you can see from my
eariler
wsdl file, if I do the following:
(1) changed the line to <element name="getSessionReturn"
type="xsd:string"
form="qualified"/>, to solve the null result problem;
(2) uncommented out the line to indicate the soap header in the return
message:
<wsdlsoap:header message="impl:soapHeader" part="sessionID"
use="literal"
/>
When invoke the getSession() call, the .net client complained:
=========================================
System.InvalidOperationException: The specified type was not recognized:
name='long',
namespace='
http://www.w3.org/2001/XMLSchema', at <sessionID
xmlns='
http://xml.apache.org/axis/session'>.
at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read1_Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read8_
OutHeaders()
Do I need to create serializer/deserializer for the SOAP header? I
thought
the created proxy code already recognize it and can serialize it
automatically, like gSoap does.
Here is the new generated client proxy:
============================
namespace MyNameSpace{
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;
/// <remarks/>
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="MynameServiceSoapBindi
ng", Namespace="urn:myname.com")]
public class MynameServiceService :
System.Web.Services.Protocols.SoapHttpClientProtocol {
public session sessionID;
/// <remarks/>
public MynameServiceService() {
this.Url = "
http://localhost:8080/services/MynameService";
}
/// <remarks/>
[System.Web.Services.Protocols.SoapHeaderAttribute("sessionID",
Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("",
RequestNamespace="urn:myname.com", ResponseNamespace="urn:myname.com",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return:
System.Xml.Serialization.XmlElementAttribute("getSessionReturn")]
public string
getSession([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Sch
ema.XmlSchemaForm.Unqualified)] string username,
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSche
maForm.Unqualified)] string password) {
object[] results = this.Invoke("getSession", new
object[]
{
username,
password});
return ((string)(results[0]));
}
/// <remarks/>
public System.IAsyncResult BegingetSession(string username,
string
password, System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("getSession", new object[] {
username,
password}, callback, asyncState);
}
/// <remarks/>
public string EndgetSession(System.IAsyncResult
asyncResult)
{
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}
/// <remarks/>
[System.Web.Services.Protocols.SoapHeaderAttribute("sessionID",
Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("",
RequestNamespace="urn:myname.com", ResponseNamespace="urn:myname.com",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public void closeSession() {
this.Invoke("closeSession", new object[0]);
}
/// <remarks/>
public System.IAsyncResult
BegincloseSession(System.AsyncCallback
callback, object asyncState) {
return this.BeginInvoke("closeSession", new object[0],
callback,
asyncState);
}
/// <remarks/>
public void EndcloseSession(System.IAsyncResult
asyncResult)
[System.Xml.Serialization.XmlTypeAttribute(Namespace="
http://xml.apache.org/
axis/session")]
[System.Xml.Serialization.XmlRootAttribute("sessionID",
Namespace="
http://xml.apache.org/axis/session", IsNullable=false)]
public class session :
System.Web.Services.Protocols.SoapHeader
{
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public string[] Text;
}
}