Re: How do you transparently implement the same web service (WSDL) with java axis and .NET ?

Tech-Archive recommends: Speed Up your PC by fixing your registry



Now I have documented all generated WSDL files and also all SOAP
messages, and have attached them below in this message.

The problem seems to be that when you take an original WSDL file and
generate Java Axis code and C# ASP.NET code,
then the Axis and ASP.NET will return different WSDL files than the
original WSDL file.

Axis generates
<wsdlsoap:operation soapAction=""/>
in the WSDL file, while Microsoft does not, but instead will give the
SOAP fault message "Server did not recognize the value of HTTP Header
SOAPAction: ."
However, that is not the only difference, but there are other
significant differences in the generated WSDL files, which you can see
futher down in this message.

I guess the key question here is one of the following:

(1) What am I doing wrong below in the commands I am using for the
code/WSDL generation ???

(2) Which tool is not following the WSDL standard ???
(The Axis team's "Java2WSDL" or "WSDL2Java", or Microsoft's "wsdl.exe"
or ASP.NET's runtime that returns a different WSDL than the original)

The rest of this message illustrates the procedure I have followed for
code generation, including all resulting WSDL files and SOAP messages.

- - - - - - - - - - -

First I manually create a java interface:

package com.myPackage;
public interface MyService {
String getMyString();
}

Then I generate a WSDL file from the above interface with this command:

java -cp .;%AXISCLASSPATH% org.apache.axis.wsdl.Java2WSDL -o
myservice.wsdl -l"http://localhost:8083/axis/services/MyService";
com.myPackage.MyService

I am using the latest Axis 1.2 final release version from the 3rd of
may 2005.

This is the WSDL file generated by the above command:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://myPackage.com";
xmlns:impl="http://myPackage.com"; xmlns:intf="http://myPackage.com";
xmlns:apachesoap="http://xml.apache.org/xml-soap";
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/";
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/";
xmlns:xsd="http://www.w3.org/2001/XMLSchema";
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/";>
<!--WSDL created by Apache Axis version: 1.2
Built on May 03, 2005 (02:20:24 EDT)-->

<wsdl:message name="getMyStringRequest">

</wsdl:message>

<wsdl:message name="getMyStringResponse">

<wsdl:part name="getMyStringReturn" type="soapenc:string"/>

</wsdl:message>

<wsdl:portType name="MyService">

<wsdl:operation name="getMyString">

<wsdl:input name="getMyStringRequest"
message="impl:getMyStringRequest"/>

<wsdl:output name="getMyStringResponse"
message="impl:getMyStringResponse"/>

</wsdl:operation>

</wsdl:portType>

<wsdl:binding name="MyServiceSoapBinding" type="impl:MyService">

<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>

<wsdl:operation name="getMyString">

<wsdlsoap:operation soapAction=""/>

<wsdl:input name="getMyStringRequest">

<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
namespace="http://myPackage.com"/>

</wsdl:input>

<wsdl:output name="getMyStringResponse">

<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
namespace="http://myPackage.com"/>

</wsdl:output>

</wsdl:operation>

</wsdl:binding>

<wsdl:service name="MyServiceService">

<wsdl:port name="MyService" binding="impl:MyServiceSoapBinding">

<wsdlsoap:address
location="http://localhost:8083/axis/services/MyService"/>

</wsdl:port>

</wsdl:service>

</wsdl:definitions>

Then I generate the java code (client proxy and server skeleton
implementation for axis):
java -cp .;%AXISCLASSPATH% org.apache.axis.wsdl.WSDL2Java -p
com.myGeneratedPackage --server-side --skeletonDeploy true
myservice.wsdl

I implement the generated class "MyServiceSoapBindingImpl" like this:

public class MyServiceSoapBindingImpl implements
com.myGeneratedPackage.MyService_PortType{
public java.lang.String getMyString() throws
java.rmi.RemoteException {
return "This is a Java Axis implementation";
}
}
(the only thing I changed in the class above was the return value,
which axis generated to null)

Then I deploy the axis service with this command:

java -cp .;%AXISCLASSPATH% org.apache.axis.client.AdminClient
-lhttp://localhost:8083/axis/services/AdminService
com\myGeneratedPackage\deploy.wsdd

Then I can access the web service at this URL:
http://localhost:8083/axis/services/MyService

And this URL will show me a WSDL file generated from the Java Axis Web
Service:
http://localhost:8083/axis/services/MyService?WSDL
and it will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://myPackage.com";
xmlns:apachesoap="http://xml.apache.org/xml-soap";
xmlns:impl="http://myPackage.com"; xmlns:intf="http://myPackage.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";>
<!--WSDL created by Apache Axis version: 1.2
Built on May 03, 2005 (02:20:24 EDT)-->

<wsdl:message name="getMyStringRequest">

</wsdl:message>

<wsdl:message name="getMyStringResponse">

<wsdl:part name="getMyStringReturn" type="soapenc:string"/>

</wsdl:message>

<wsdl:portType name="MyService">

<wsdl:operation name="getMyString">

<wsdl:input message="impl:getMyStringRequest"
name="getMyStringRequest"/>

<wsdl:output message="impl:getMyStringResponse"
name="getMyStringResponse"/>

</wsdl:operation>

</wsdl:portType>

<wsdl:binding name="MyServiceSoapBinding" type="impl:MyService">

<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>

<wsdl:operation name="getMyString">

<wsdlsoap:operation soapAction=""/>

<wsdl:input name="getMyStringRequest">

<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
namespace="http://myPackage.com"; use="encoded"/>

</wsdl:input>

<wsdl:output name="getMyStringResponse">

<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
namespace="http://myPackage.com"; use="encoded"/>

</wsdl:output>

</wsdl:operation>

</wsdl:binding>

<wsdl:service name="MyServiceService">

<wsdl:port binding="impl:MyServiceSoapBinding" name="MyService">

<wsdlsoap:address
location="http://localhost:8083/axis/services/MyService"/>

</wsdl:port>

</wsdl:service>

</wsdl:definitions>

As far as I can see, the only difference between the above WSDL
generated from the Axis Web service and the original WSDL futher up is
that the orders of the attributes are sometimes different.

Then I set up the axis utility TCPMonitor so that port 8155 redirects
to port 8083 and implemented a client like this:

import com.myGeneratedPackage.MyServiceServiceLocator;
import com.myGeneratedPackage.MyService_PortType;
public class MyServiceClient {
public static void main(String[] args) throws Exception {
MyServiceServiceLocator myServiceLocator = new
MyServiceServiceLocator();
MyService_PortType myService = myServiceLocator.getMyService(
new URL("http://localhost:8155/axis/services/MyService";)
);
String myString = myService.getMyString();
System.out.println("Result: " + myString);
}
}

(both the class "MyServiceServiceLocator" and the interface
"MyService_PortType" above were generated above further up by the axis
tool WSDL2Java)

When I run the code above it works fine, and when I look at the
TCPMonitor output, here is the SOAP request:

POST /axis/services/MyService HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related,
text/*
User-Agent: Axis/1.2
Host: 127.0.0.1
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 378

<?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:Body>
<ns1:getMyString
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
xmlns:ns1="http://myPackage.com"/>
</soapenv:Body>
</soapenv:Envelope>

and here is the SOAP response:

HTTP/1.1 200 OK
Content-Type: text/xml;charset=utf-8
Date: Tue, 10 May 2005 19:12:13 GMT
Server: Apache-Coyote/1.1
Connection: close

<?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:Body>
<ns1:getMyStringResponse
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
xmlns:ns1="http://myPackage.com";>
<getMyStringReturn xsi:type="soapenc:string"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/";>This is a
Java Axis implementation</getMyStringReturn>
</ns1:getMyStringResponse>
</soapenv:Body>
</soapenv:Envelope>

OK, so far I have only done a java only implementation, i.e. I have
made a web service client which can invoke a web service, where both
the client proxy and the server skeleton has been generated with java
axis.

Now, it is time to create a web service with C# and ASP.NET, using the
same WSDL interface (myservice.wsdl) as above.

I now use the wsdl.exe tool like this:

wsdl.exe myservice.wsdl /server /namespace:com.myGeneratedPackage
/out:MyService.cs

The above command generated the following "MyService.cs" asbtract
class:

namespace com.myGeneratedPackage {
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;
/// <remarks/>

[System.Web.Services.WebServiceBindingAttribute(Name="MyServiceSoapBinding",
Namespace="http://myPackage.com";)]
public abstract class MyServiceService :
System.Web.Services.WebService {
/// <remarks/>
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapRpcMethodAttribute("",
RequestNamespace="http://myPackage.com";,
ResponseNamespace="http://myPackage.com";)]
[return:
System.Xml.Serialization.SoapElementAttribute("getMyStringReturn")]
public abstract string getMyString();
}
}

Now I create a web service "MyConcreteService.asmx" with Visual
Studio.NET 2003.
Then I go into the code for "MyConcreteService.asmx.cs" and implement
(override) the abstract class and change the inheritance to make it
inherit from MyServiceService instead of inheriting from
System.Web.Services.WebService.
Also, I add the [WebMethod] attribute.
Now this class looks like this:

public class MyConcreteService : MyServiceService
{
public MyConcreteService()
{
//CODEGEN: This call is required by the ASP.NET Web Services
Designer
InitializeComponent();
}
[WebMethod]
public override string getMyString()
{
return "This is a C# ASP.NET implementation";
}

#region Component Designer generated code

//Required by the Web Services Designer
private IContainer components = null;

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}

#endregion
}

Now I can access the web service at this URL:
http://localhost/WebServices/MyConcreteService.asmx

And this URL will show me a WSDL file generated from IIS/ASP.NET:
http://localhost/WebServices/MyConcreteService.asmx?WSDL
and it will look like this:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/";
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/";
xmlns:s="http://www.w3.org/2001/XMLSchema";
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/";
xmlns:tns="http://tempuri.org/";
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/";
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/";
targetNamespace="http://tempuri.org/";
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/";>
<wsdl:types>
<s:schema elementFormDefault="qualified"
targetNamespace="http://tempuri.org/";>
<s:element name="getMyString">
<s:complexType />
</s:element>
<s:element name="getMyStringResponse">
<s:complexType>
<s:sequence>

<s:element minOccurs="0" maxOccurs="1"
name="getMyStringResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="getMyStringSoapIn">
<wsdl:part name="parameters" element="tns:getMyString" />
</wsdl:message>

<wsdl:message name="getMyStringSoapOut">
<wsdl:part name="parameters" element="tns:getMyStringResponse" />
</wsdl:message>
<wsdl:portType name="MyConcreteServiceSoap">
<wsdl:operation name="getMyString">
<wsdl:input message="tns:getMyStringSoapIn" />
<wsdl:output message="tns:getMyStringSoapOut" />
</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="MyConcreteServiceSoap"
type="tns:MyConcreteServiceSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http";
style="document" />
<wsdl:operation name="getMyString">
<soap:operation soapAction="http://tempuri.org/getMyString";
style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />

</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MyConcreteService">
<documentation xmlns="http://schemas.xmlsoap.org/wsdl/"; />
<wsdl:port name="MyConcreteServiceSoap"
binding="tns:MyConcreteServiceSoap">
<soap:address
location="http://localhost/WebServices/MyConcreteService.asmx"; />
</wsdl:port>
</wsdl:service>

</wsdl:definitions>

Obviously the above WSDL is very different from the original one, which
did not even have any wsdl:types element.
Another big difference is the targetNamespace="http://tempuri.org/";
versus the original targetNamespace="http://myPackage.com";
But maybe the most significant difference (considering the below SOAP
error message) is the fact that the following element:
<wsdlsoap:operation soapAction=""/>
does not occurr in the ASP.NET generated WSDL, which it did in the
original WSDL file above that I used for all code generation.

For the sake of completness I will nelow continue with illustrating the
SOAP requests and responses when I try to execute this .NET service
from this java axis proxy:

MyServiceServiceLocator myServiceLocator = new
MyServiceServiceLocator();
MyService_PortType myService = myServiceLocator.getMyService(
new
URL("http://localhost:8156/WebServices/MyConcreteService.asmx?WSDL";)
);
String myString = myService.getMyString();
System.out.println("Result: " + myString);
(before the execution of this code above, I have set up redirection of
port 8156 to port 80 in TCPMonitor)

The SOAP request:

POST /WebServices/MyConcreteService.asmx?WSDL HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related,
text/*
User-Agent: Axis/1.2
Host: 127.0.0.1
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 378

<?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:Body>
<ns1:getMyString
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
xmlns:ns1="http://myPackage.com"/>
</soapenv:Body>
</soapenv:Envelope>


The SOAP response:

HTTP/1.1 500 Internal Server Error.
Server: Microsoft-IIS/5.1
Date: Tue, 10 May 2005 19:57:59 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 1.1.4322
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Content-Length: 453

<?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>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Server did not recognize the value of HTTP
Header SOAPAction: .</faultstring>
<detail />
</soap:Fault>
</soap:Body>
</soap:Envelope>

/ Tom

.



Relevant Pages

  • Re: Newbie question - how to use Web Service function in Access
    ... what is wrong with the SOAP toolkit form Microsoft? ... possible to define something other than a web service with WSDL? ... Have the developers given you a WSDL file? ... the data from the Access table to SQL Server via the web service ...
    (microsoft.public.dotnet.framework.aspnet.webservices)
  • Re: Soap toolkit completely replaced by .NET? Im not so sure...
    ... I posted used no dynamic recompilation, however it made use of a ... web service without recompiling the proxy class (other than manually ... creating an HTTP GET/POST or SOAP message) then I'd like to see it. ... >> can take a WSDL file, come up with a list of service methods, and call ...
    (microsoft.public.dotnet.framework.webservices)
  • Re: Newbie question - how to use Web Service function in Access
    ... what is wrong with the SOAP toolkit form Microsoft? ... possible to define something other than a web service with WSDL? ... Have the developers given you a WSDL file? ... in xml tags and send it to SQL Server, but I have no idea how to ...
    (microsoft.public.dotnet.framework.aspnet.webservices)
  • Re: Newbie question - how to use Web Service function in Access
    ... SOAP somewhere. ... possible to define something other than a web service with WSDL? ... Have the developers given you a WSDL file? ... in xml tags and send it to SQL Server, but I have no idea how to ...
    (microsoft.public.dotnet.framework.aspnet.webservices)
  • Re: Newbie question - how to use Web Service function in Access
    ... If there was no SOAP in sight, then it wasn't a web service you were ... Passing XML around is not the same thing as calling a web service. ... Have the developers given you a WSDL file? ...
    (microsoft.public.dotnet.framework.aspnet.webservices)