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

Discussion in 'ASP .Net Web Services' started by tomjbr.10216233@bloglines.com, May 10, 2005.

  1. Guest

    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
     
    , May 10, 2005
    #1
    1. Advertising

  2. "" <> wrote in
    news::
    > 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.



    --
    Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
    "Programming is an art form that fights back"

    Blog: http://blogs.atozed.com/kudzu
     
    Chad Z. Hower aka Kudzu, May 10, 2005
    #2
    1. Advertising

  3. Guest

    "Chad Z. Hower aka Kudzu" wrote:
    >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
     
    , May 10, 2005
    #3
  4. "" <> wrote in
    news::
    >>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 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?


    --
    Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
    "Programming is an art form that fights back"

    Blog: http://blogs.atozed.com/kudzu
     
    Chad Z. Hower aka Kudzu, May 10, 2005
    #4
  5. You will find useful information at -

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

    <> wrote in message
    news:...
    > 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
    >
     
    Ajay Choudhary, May 10, 2005
    #5
  6. Guest

    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
     
    , May 10, 2005
    #6
  7. Guest

    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
     
    , May 10, 2005
    #7
  8. Guest

    >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
     
    , May 10, 2005
    #8
  9. Guest

    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
     
    , May 10, 2005
    #9
  10. "" <> wrote in
    news::
    > 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.


    --
    Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
    "Programming is an art form that fights back"

    Blog: http://blogs.atozed.com/kudzu
     
    Chad Z. Hower aka Kudzu, May 11, 2005
    #10
  11. Guest

    >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
     
    , May 11, 2005
    #11
  12. Guest

    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
     
    , May 11, 2005
    #12
  13. "" <> wrote in
    news::
    > 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.


    There is, its really easy:

    Admin = new AdminWS.Admin();
    if (!aLocal) {
    Admin.Url = "https://xxxxxxxx/xxxx.asmx";
    }



    --
    Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
    "Programming is an art form that fights back"

    Blog: http://blogs.atozed.com/kudzu
     
    Chad Z. Hower aka Kudzu, May 11, 2005
    #13
  14. Guest

    > 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.


    >There is, its really easy:


    >Admin = new AdminWS.Admin();
    >if (!aLocal) {
    > Admin.Url = "https://xxxxxxxx/xxxx.asmx";
    >}


    Yes, you are right, that was embarrassingly easy :)
    / Tom
     
    , May 12, 2005
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page