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

T

tomjbr.10216233

When I have tried to generate java and C# servers/clients from the same
WSDL as described further below, these are the results I have been able
to achieve:
OK: C# proxy invokes C# service
OK: C# proxy invokes Java service
OK: Java proxy invokes Java service
NOT OK: Java proxy invokes C# service

When I try to invoke a C# web service with a java axis client I get the
error message:
"Server did not recognize the value of HTTP Header SOAPAction: ."

I have been struggling with implementing web services with java and
..NET that are supporting the same WSDL and to be able to reuse client
code that are using these services.
To be more specific, I would like to implement the very same (from a
WSDL point of view) web service with both Java Axis and C# (as an
ASP.NET web services).
For both of these two servers, I would then like to create one client
with Java Axis and one client with C# that can reuse these two services
through polymorphistic invocations of a common interface.

My key question is:

Where can I find code examples that describe the best way to create
java axis clients/servers and .NET web services clients/servers which
can communicate with each other in a transparent way ???

I mean, since the location transparency is often described as a key
issue in a SOA implemented with web services then this should be a very
common problem ?
Anyone who is using UDDI to look up implementations of a certain WSDL
that is pointed to from a tModel in an UDDI server should have run into
this kind of problem, when you want to dynamically bind to different
implementations of the same WSDL interface...
(though, maybe not too many people are actually using UDDI in reality,
and maybe UDDI still essentially just occurrs on nice power point
slides showing what you can do with web services...)

This is the kind of approach I have tried:

1. Define a normal java interface

2. Generate a WSDL file from that java interface by using the java axis
tool "org.apache.axis.wsdl.Java2WSDL"

3. Generate java client and service code from the WSDL file by using
the java axis tool "org.apache.axis.wsdl.WSDL2Java" (including the
interface "MyServiceInterface" and the class "MyServiceLocator" in the
code below and also including a skeleton server class
"MyServiceSoapBindingImpl" where I then put the implementation)

4. Generate an abstract C# class from the WSDL file by using the MS
tool "wsdl.exe"

5. Create a web service "service.asmx" (with Visual Studio.NET 20003)
and manually change it so it inherits from the class generated in the
previous step 4, instead of the default inheritance from
"System.Web.Services.WebService".
In this subclass (Service1.asmx.cs) I then implement the abstract
methods and tag them with "[WebMethod]"

6. Manually define a C# interface ( "IMyWebServiceInterface" in the
code further below with the C# web service methods)

7. Generate a C# client proxy class for the java axis web service
(which I of course deployed after step 3 above) by adding a web
reference in VS.NET 2003 and then pointing to the WSDL file.

8. Manually edit the proxy class generated in step 7 above (the class
that inherits from "SoapHttpClientProtocol") so that it also implements
the interface I created in step 6 above.

9. Repeat step 7 och 8 above to create a C# proxy class that can use
the C# web service through that same C# interface created in step 6.

The only thing that I can not make work is the java axis client to
invoke the C# web service.
When I do it, I get the following SOAP faultstring message:
"Server did not recognize the value of HTTP Header SOAPAction: ."

I believe that the reason for the trouble is that the ASP.NET web
service does not generate exactly the same WSDL as the original WSDL.
In other words, when I generated the abstract C# class from the WSDL
file by using the MS tool wsdl.exe and then created a "service.asmx"
that I then let inherit from this generated class, then when I run
"service.asmx?wsdl" in a web browser then it is not exactly the same
WSDL as the original.

So the question is what should I do instead of the stuff I described
above, when I want to create java axis and .NET clients/servers that
can communicate with each other ???

Below I provide some code, just in case it would be unclear what I am
trying to do.

Here is the kind of end result code with a Java Axis client that I
would like to be able to use:

String webserviceURLs[] = new String[]{
"http://www.csharpedomain.com/service.asmx",
"http://www.javadomain.com/axis/services/JavaWebService"
};
MyServiceInterface myService;
MyServiceLocator myServiceLocator = new MyServiceLocator();
for (int i = 0; i < webserviceURLs.length; i++) {
myService = myServiceLocator.getMyService(webserviceURLs);
myService.myMethod(); // the polymorphistic invocation
}

Here is the kind of end result code with a C# client that I was able to
use:

public void someMethod()
{
IMyWebServiceInterface[] webServiceInterfaces = getWebServiceProxys();
foreach(IMyWebServiceInterface webServiceProxy in
webServiceInterfaces)
{
webServiceProxy.getServiceBeskrivning(); // the polymorphistic
invocation
}
}

private IMyWebServiceInterface[] getWebServiceProxys()
{
IMyWebServiceInterface[] webServiceInterfaces = new
IMyWebServiceInterface[2];
webServiceInterfaces[0] = new localhost_java_MyService();
webServiceInterfaces[1] = new localhost_csharpe_MyService();
return webServiceInterfaces;
}

However, I would prefer if there was some easier way to create a C#
client that transparently (through polymorphism) can invoke the
services than to manually create the interface "IMyWebServiceInterface"
and instantiate the concrete classes as above, i.e. I would prefer to
do something that is more like the axis client above where you can
provide url strings to the implementations of the web services that
supports the same WSDL.

/ Tom
 
C

Chad Z. Hower aka Kudzu

I have been struggling with implementing web services with java and
NET that are supporting the same WSDL and to be able to reuse client
code that are using these services.

I think this may prove difficult since ASP.NET webservices focus on
generating the WSDL for you based on C#/VB interfaces.
 
T

tomjbr.10216233

Chad Z. Hower aka Kudzu said:
I think this may prove difficult since ASP.NET webservices focus on
generating the WSDL for you based on C#/VB interfaces.

Well, it is possible to use a C# interface after it has been added
manually to the generated proxies.
I did illustrate it above, and by the way I got the idea from the "Web
Service Interface pattern" in the book ".NET patterns" from 2003 by
Christian Thilmany. Though, I am not sure whether that book was written
before or after .NET 1.1 or Visual Studio.NET 2003. Since the manual
process is not optimal I was hoping that there would be a better way,
but maybe there is not.

Anyway, the main problem was how to let the java axis client invoke a
C# web service, in a transparent way, i.e. I want to let the java
client use an interface that can be used for dynamically invoking
either a java web service or a C# web service.

I can not believe this should be so difficult, so let us then talk a
little about what UDDI is supposed to be able to do for us.
If you are using UDDI, you can use the "find_binding" message with a
tModelKey (that for example can be used as a key to a certain WSDL
interface) as a parameter.
The resulting return message of "find_binding" is a list of
"bindingTemplate" structures where each such template contains an
"accesssPoint" element which contains an URL to a web service which
supports the certain WSDL.

Now then, when I from an UDDI server have got this list of URL's to web
services supporting the requested WSDL interface, how can I then
dynamically connect to these web services ???
I can indeed do it in runtime with many java axis web services, but one
important aspect of a SOA (i.e. web services) is also the
implementation transparency, i.e. it should be possible to connect to
..NET for example (if I would be interested in java only, then I could
use RMI instead)

/ Tom
 
C

Chad Z. Hower aka Kudzu

Well, it is possible to use a C# interface after it has been added
manually to the generated proxies.

I didnt say it was impossible, I said it would prove difficult.
Anyway, the main problem was how to let the java axis client invoke a
C# web service, in a transparent way, i.e. I want to let the java
client use an interface that can be used for dynamically invoking
either a java web service or a C# web service.

I would ask this on a Java group as the problem appears to be with Java
interpreting the WSDL. Ive not consumed C# web services from Java, but I
have consumed them without trouble in Delphi (Win32 and .NET).
Now then, when I from an UDDI server have got this list of URL's to web
services supporting the requested WSDL interface, how can I then
dynamically connect to these web services ???
I can indeed do it in runtime with many java axis web services, but one
important aspect of a SOA (i.e. web services) is also the
implementation transparency, i.e. it should be possible to connect to
NET for example (if I would be interested in java only, then I could
use RMI instead)

If you know what type of service you are looking for with UDDI, you could
pregenerate each of the interface types before as well no?
 
A

Ajay Choudhary

You will find useful information at -

http://msdn.microsoft.com/library/d...html/ASPNet-JSPMig-WebServicesIntegration.asp

When I have tried to generate java and C# servers/clients from the same
WSDL as described further below, these are the results I have been able
to achieve:
OK: C# proxy invokes C# service
OK: C# proxy invokes Java service
OK: Java proxy invokes Java service
NOT OK: Java proxy invokes C# service

When I try to invoke a C# web service with a java axis client I get the
error message:
"Server did not recognize the value of HTTP Header SOAPAction: ."

I have been struggling with implementing web services with java and
.NET that are supporting the same WSDL and to be able to reuse client
code that are using these services.
To be more specific, I would like to implement the very same (from a
WSDL point of view) web service with both Java Axis and C# (as an
ASP.NET web services).
For both of these two servers, I would then like to create one client
with Java Axis and one client with C# that can reuse these two services
through polymorphistic invocations of a common interface.

My key question is:

Where can I find code examples that describe the best way to create
java axis clients/servers and .NET web services clients/servers which
can communicate with each other in a transparent way ???

I mean, since the location transparency is often described as a key
issue in a SOA implemented with web services then this should be a very
common problem ?
Anyone who is using UDDI to look up implementations of a certain WSDL
that is pointed to from a tModel in an UDDI server should have run into
this kind of problem, when you want to dynamically bind to different
implementations of the same WSDL interface...
(though, maybe not too many people are actually using UDDI in reality,
and maybe UDDI still essentially just occurrs on nice power point
slides showing what you can do with web services...)

This is the kind of approach I have tried:

1. Define a normal java interface

2. Generate a WSDL file from that java interface by using the java axis
tool "org.apache.axis.wsdl.Java2WSDL"

3. Generate java client and service code from the WSDL file by using
the java axis tool "org.apache.axis.wsdl.WSDL2Java" (including the
interface "MyServiceInterface" and the class "MyServiceLocator" in the
code below and also including a skeleton server class
"MyServiceSoapBindingImpl" where I then put the implementation)

4. Generate an abstract C# class from the WSDL file by using the MS
tool "wsdl.exe"

5. Create a web service "service.asmx" (with Visual Studio.NET 20003)
and manually change it so it inherits from the class generated in the
previous step 4, instead of the default inheritance from
"System.Web.Services.WebService".
In this subclass (Service1.asmx.cs) I then implement the abstract
methods and tag them with "[WebMethod]"

6. Manually define a C# interface ( "IMyWebServiceInterface" in the
code further below with the C# web service methods)

7. Generate a C# client proxy class for the java axis web service
(which I of course deployed after step 3 above) by adding a web
reference in VS.NET 2003 and then pointing to the WSDL file.

8. Manually edit the proxy class generated in step 7 above (the class
that inherits from "SoapHttpClientProtocol") so that it also implements
the interface I created in step 6 above.

9. Repeat step 7 och 8 above to create a C# proxy class that can use
the C# web service through that same C# interface created in step 6.

The only thing that I can not make work is the java axis client to
invoke the C# web service.
When I do it, I get the following SOAP faultstring message:
"Server did not recognize the value of HTTP Header SOAPAction: ."

I believe that the reason for the trouble is that the ASP.NET web
service does not generate exactly the same WSDL as the original WSDL.
In other words, when I generated the abstract C# class from the WSDL
file by using the MS tool wsdl.exe and then created a "service.asmx"
that I then let inherit from this generated class, then when I run
"service.asmx?wsdl" in a web browser then it is not exactly the same
WSDL as the original.

So the question is what should I do instead of the stuff I described
above, when I want to create java axis and .NET clients/servers that
can communicate with each other ???

Below I provide some code, just in case it would be unclear what I am
trying to do.

Here is the kind of end result code with a Java Axis client that I
would like to be able to use:

String webserviceURLs[] = new String[]{
"http://www.csharpedomain.com/service.asmx",
"http://www.javadomain.com/axis/services/JavaWebService"
};
MyServiceInterface myService;
MyServiceLocator myServiceLocator = new MyServiceLocator();
for (int i = 0; i < webserviceURLs.length; i++) {
myService = myServiceLocator.getMyService(webserviceURLs);
myService.myMethod(); // the polymorphistic invocation
}

Here is the kind of end result code with a C# client that I was able to
use:

public void someMethod()
{
IMyWebServiceInterface[] webServiceInterfaces = getWebServiceProxys();
foreach(IMyWebServiceInterface webServiceProxy in
webServiceInterfaces)
{
webServiceProxy.getServiceBeskrivning(); // the polymorphistic
invocation
}
}

private IMyWebServiceInterface[] getWebServiceProxys()
{
IMyWebServiceInterface[] webServiceInterfaces = new
IMyWebServiceInterface[2];
webServiceInterfaces[0] = new localhost_java_MyService();
webServiceInterfaces[1] = new localhost_csharpe_MyService();
return webServiceInterfaces;
}

However, I would prefer if there was some easier way to create a C#
client that transparently (through polymorphism) can invoke the
services than to manually create the interface "IMyWebServiceInterface"
and instantiate the concrete classes as above, i.e. I would prefer to
do something that is more like the axis client above where you can
provide url strings to the implementations of the web services that
supports the same WSDL.

/ Tom
 
T

tomjbr.10216233

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:eek:peration 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:eek:peration name="getMyString">

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

<wsdl:eek:utput name="getMyStringResponse"
message="impl:getMyStringResponse"/>

</wsdl:eek:peration>

</wsdl:portType>

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

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

<wsdl:eek:peration name="getMyString">

<wsdlsoap:eek:peration soapAction=""/>

<wsdl:input name="getMyStringRequest">

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

</wsdl:input>

<wsdl:eek:utput name="getMyStringResponse">

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

</wsdl:eek:utput>

</wsdl:eek:peration>

</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:eek:peration name="getMyString">

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

<wsdl:eek:utput message="impl:getMyStringResponse"
name="getMyStringResponse"/>

</wsdl:eek:peration>

</wsdl:portType>

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

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

<wsdl:eek:peration name="getMyString">

<wsdlsoap:eek:peration soapAction=""/>

<wsdl:input name="getMyStringRequest">

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

</wsdl:input>

<wsdl:eek:utput name="getMyStringResponse">

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

</wsdl:eek:utput>

</wsdl:eek:peration>

</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:eek:peration name="getMyString">
<wsdl:input message="tns:getMyStringSoapIn" />
<wsdl:eek:utput message="tns:getMyStringSoapOut" />
</wsdl:eek:peration>
</wsdl:portType>

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

</wsdl:eek:utput>
</wsdl:eek:peration>
</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:eek:peration 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
 
T

tomjbr.10216233

Well, thank you but I do not think it is too useful these days.
That page is from October 2003, and is just at the bottom mentioning
"Axis, also known as Apache SOAP 3.0", and the page describes Apache
SOAP which did not even support WSDL.

/ Tom
 
T

tomjbr.10216233

If you know what type of service you are looking for with UDDI,
you could pregenerate each of the interface types before as well no?

Well, yes I am generating everything.
First I generate the WSDL file from a java interface, and then I
generate client proxies and server skeletons (in both java and C#) from
the WSDL file.

But I am not quite sure what your point was here.
Maybe you mean that I can look for one particular service, and then
find a WSDL file and generate a proxy for that service. Then I can find
another kind of service with another WSDL file and generate a proxy for
that service.
Sure I could do that, but that is not what I want to do.

The thing I want to do is to be able to invoke multiple web services
which are supporting the same WSDL interface.

And I want to do it with polymorphism, so I can do it dynamically when
I in runtime find a new URL supporting the same WSDL interface, without
having to generate a new class each time.

And my point of doing the UDDI comparison was that just if you can not
even do this stuff with hardcoding some URL strings (which I have
tried) , then how are you supposed to implement software that are using
an UDDI server to dynamically find and bind to URL's that support a
certain WSDL interface that has been registered in an UDDI tModel
structure.

/ Tom
 
T

tomjbr.10216233

I now think the problem may have something to do with the Java2WSDL
argument "-A, --soapAction <argument>" which I have not been using.
When I run Java2WSDL it generates this:
<wsdlsoap:eek:peration soapAction=""/>
and .NET will then be complaining about "Server did not recognize the
value of HTTP Header SOAPAction: ."

Though, I do not really understand exactly what I should do about it.
As far as I understand, the soapAction attribute should be an URL, but
on the other hand it does not make any sense to me to specify a URL in
an interface that will be used for generating different implementations
that will have different URL's.

So maybe I am misunderstanding something conceptually essential about
why a SOAPAction (URL?) should be in an interface ?

/ Tom
 
C

Chad Z. Hower aka Kudzu

The thing I want to do is to be able to invoke multiple web services
which are supporting the same WSDL interface.

If this is the case - isnt it a matter of just using one webservice client
and changing the URL? Or have I overlooked something?

I have webservices that are published at multiple locations, and I merely
change the URL in the client to point them at the right place.
And I want to do it with polymorphism, so I can do it dynamically when
I in runtime find a new URL supporting the same WSDL interface, without
having to generate a new class each time.

Im not sure where polymorphism fits into this, but if you dont want to
generate, and if they are new interfaces, then you are going to have to
manually parse the WSDL.
And my point of doing the UDDI comparison was that just if you can not
even do this stuff with hardcoding some URL strings (which I have
tried) , then how are you supposed to implement software that are using
an UDDI server to dynamically find and bind to URL's that support a
certain WSDL interface that has been registered in an UDDI tModel
structure.

Because users consume the interface before hand, then when they find it
with UDDI they just change the URL that the webservice client code connects
to.
 
T

tomjbr.10216233

If this is the case - isnt it a matter of just using one webservice
client and changing the URL? Or have I overlooked something?
I have webservices that are published at multiple locations, and I
merely change the URL in the client to point them at the right place.
Im not sure where polymorphism fits into this,

I do not know how you can do it in Delphi, but with Java Axis code, you
are using a client like this:

MyServiceServiceLocator myServiceLocator = new
MyServiceServiceLocator();
MyService_PortType myService = myServiceLocator.getMyService(
new URL("http://localhost:8156/WebServices/MyConcreteService.asmx")
);
String myString = myService.getMyString(); // the polymorphistic
invocation

In the code above, "MyServiceServiceLocator" is a generated class and
"MyService_PortType" is a generated interface.
The generated method "getMyService" instantiates and return a new
object that implement the interface, and this object will take care of
the invocation to the URL specified as parameter.

When creating a C# client, (as described in step 6-8 in my first
message in this thread), the best thing I have been able to come up
with to transparently do invocations to services supporting the same
interface, is to manually create an interface (IMyWebServiceInterface
below) and then create a factory method like this:

IMyWebServiceInterface[] webServiceProxies =
getWebServiceProxys();
foreach(IMyWebServiceInterface webServiceProxy in
webServiceProxies)
{
String myString = webServiceProxy.getMyString(); // the polymorphistic
invocation
}

private IMyWebServiceInterface[] getWebServiceProxys()
{
IMyWebServiceInterface[] webServiceInterfaces = new
IMyWebServiceInterface[2];
webServiceInterfaces[0] = new localhost_java_MyService();
webServiceInterfaces[1] = new localhost_csharpe_MyService();
return webServiceInterfaces;

}

Essentially though, you are right and can consider it as switching URL,
and that would be OK for me, if there would be any methods for just
switching the URL in the generated proxy classes.

/ Tom
 
T

tomjbr.10216233

Well, I do not believe anymore that the soapAction attribute (within
"wsdlsoap:eek:peration" within "wsdl:binding") really has to be a physical
URL, and definitely I do not think it should be the web service URL,
since that one is specified in the wsdlsoap:address element (within
"wsdl:service")

But since .NET was complaining about
"Server did not recognize the value of HTTP Header SOAPAction: ."
I have now tried to generate a soapAction "getMyString" with Java2WSDL,
but eventually ASP.NET will still complain with the message:
"Server did not recognize the value of HTTP Header SOAPAction:
getMyString."

Any concrete suggestions about what I should do to make it work ???

Below I am showing what I have tried to do:

I was now using the parameter "-A OPERATION" to the Java2WSDL as below:

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

The above command will now generate the following WSDL file
myservice.wsdl :
( one difference is: <wsdlsoap:eek:peration soapAction="getMyString"/>
instead of an empty string as soapAction value )

<?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:eek:peration name="getMyString">

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

<wsdl:eek:utput name="getMyStringResponse"
message="impl:getMyStringResponse"/>

</wsdl:eek:peration>

</wsdl:portType>

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

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

<wsdl:eek:peration name="getMyString">

<wsdlsoap:eek:peration soapAction="getMyString"/>

<wsdl:input name="getMyStringRequest">

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

</wsdl:input>

<wsdl:eek:utput name="getMyStringResponse">

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

</wsdl:eek:utput>

</wsdl:eek:peration>

</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 proxy as before from the above WSDL.

I now run the same wsdl.exe command as before, i.e.
wsdl.exe myservice.wsdl /server /namespace:com.myGeneratedPackage
/out:MyService.cs

And it will now generate this code in the class MyService.cs :

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("getMyString",
RequestNamespace="http://myPackage.com",
ResponseNamespace="http://myPackage.com")]
[return:
System.Xml.Serialization.SoapElementAttribute("getMyStringReturn")]
public abstract string getMyString();
}
}

The only difference from before in "MyService.cs" is :
[System.Web.Services.Protocols.SoapRpcMethodAttribute("getMyString"
....
instead of as before:
[System.Web.Services.Protocols.SoapRpcMethodAttribute("" ...

The resulting SOAP request:

POST /WebServices/MyConcreteService.asmx 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: "getMyString"
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>

Obviously the generated java axis proxy was now changed to set the
SOAPAction.
(when looking in the generated java code I see this statement:
_oper.setSoapAction("getMyString"); )

The resulting SOAP response:

HTTP/1.1 500 Internal Server Error.
Server: Microsoft-IIS/5.1
Date: Wed, 11 May 2005 09:39:12 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 1.1.4322
Cache-Control: private
Content-Type: text/xml; charset=utf-8

<?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: getMyString.</faultstring>
<detail />
</soap:Fault>
</soap:Body>
</soap:Envelope>

Obviously something is still wrong, so what should I do to make it work
???

/ Tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,692
Latest member
JenniferTi

Latest Threads

Top