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

WSDL for complex types from Java to VB.Net

102 views
Skip to first unread message

George T. Bone

unread,
Sep 17, 2001, 3:13:43 PM9/17/01
to
I need help or some indirection about where to find out how to use a
complex type like:
<s:element name="Learn">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="Teach"
type="s0:LearnStruct"/>
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="LearnStruct">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="Course"
nillable="true" type="s:string"/>
<s:element minOccurs="1" maxOccurs="1" name="Teacher"
nillable="true" type="s:string"/>
<s:element minOccurs="1" maxOccurs="1" name="CreditHours"
type="s:int"/>
<s:element minOccurs="1" maxOccurs="1" name="IsFree"
type="s:boolean"/>
</s:sequence>
</s:complexType>


But I want to allow it to be usable in a VB.Net WebService
Application.
And I want to see early binding.

Problem is, when I do Add Web Reference, it doesn't "find" it
properly. If I do add it, I don't get early binding for complex
types.

So my immediate question is about there being some trick to complex
types that is unwritten. Actually, it's a stretch to find any good
examples of complex types at all, though I did figure our the new
"structure" keyword in VB.Net, and used XML Notepad to look at it's
WSDL using the ?WSDL get.
But not much of anything about using complex Java structures. Total
discovery!
So if you have done this, posting may be a better solutions since
there is Not a thing out there just yet.

Web

George T. Bone

unread,
Sep 19, 2001, 3:34:58 PM9/19/01
to
Either noone has done complex types or what?

webser...@lycos.com (George T. Bone) wrote in message news:<134c3016.01091...@posting.google.com>...

Scott Seely

unread,
Sep 21, 2001, 1:51:09 PM9/21/01
to
George,

I am assuming that you are using the IBM Web Services Toolkit to generate
the WSDL. This toolkit uses the 1999 XSD namespace (and it has a tendency to
generate invalid WSDL files). You need to fix the WSDL so that our tools can
read it. I've written an article describing what to do-- which should be
going into the KB "Real Soon Now". Here it is, in its entirety. I can't
guarantee that this is the final form as it hasn't gone through editorial
yet.

1 How To: Integrate .NET client with Apache web service
This article explains how to integrate a .NET client with an Apache SOAP
based Web Service. This article assumes that a Web Services Description
Language file exists and was created using the IBM Web Services Toolkit.

Requirements

The following items describe the recommended hardware, software, network
infrastructure, skills and knowledge and service packs you will need.

· Windows NT 4.0 (SP 6), 2000 (SP1), XP.

· IIS version 4.0, 5.0, or 6.0

· .NET Framework SDK

Prior Knowledge required

Must know how to read and edit Web Service Description Language (WSDL)
files.

1 Getting the WSDL file ready for .NET
The IBM Web Services Toolkit places the WSDL information in two files. One
file will be named [Java class name]_Service.wsdl (i.e. the Service file).
The other is named [Java class name]_Service-interface.wsdl (i.e. the
Interface file). The first file contains the service information. The second
file contains the message, portType, and binding definitions. Because of
incompatibilities between the IBM generated WSDL and the .NET WSDL
implementation, the files generated by the IBM Web Services Toolkit need to
be edited so that the .NET environment can read them in.

Note that the .NET environment can handle WSDL imports. The WSDL that the
IBM Web Services Toolkit generates contains improper usage of the
targetNamespace attribute and it incorrectly references other internal
elements (specifically the binding, message, and portType elements). The
easiest and quickest thing to do is to merge the files and edit
appropriately. Here is what to do:

1. Copy both WSDL files to your machine.

2. Open the Service file and delete the <import>.</import> element.

3. Open the Interface file and copy all elements except for the
definitions tags. Paste those elements into the Service file, above the
service element.

4. In the portType elements, append the string "tns:" to the value
listed for the message attribute listed for the input and output
sub-elements.

5. For the binding element, append the string "tns:" to the type
attribute value.

6. For the service element, append the string "tns:" to the binding and
name attribute values on the port sub-element.

7. For the root level definitions element, set the xmlns:xsd namespace
to reference the http://www.w3.org/2001/XMLSchema URI. (i.e. change 1999 to
2001)

2 Create the proxy
You can create the proxy in one of two ways. You can either use the WSDL.EXE
tool and include the file in a project or you can create a Web Reference
from within the VS .NET IDE.

Using WSDL.EXE

1. Select Start, Programs, Microsoft Visual Studio.NET 7.0, Visual
Studio.NET Tools, Visual Studio.NET Command Prompt.

2. At the command prompt, navigate to the directory that contains the
edited WSDL file.

3. Run the following command: wsdl [Java class name]_Service.wsdl.

This produces a C# language file for you to include in your project. If you
want WSDL.EXE to create the proxy in a different language, use the /language
switch.

· Visual Basic: wsdl [Java class name_Service.wsdl] /language:VB

· JavaScript: wsdl [Java class name_Service.wsdl] /language:JS

· C#: wsdl [Java class name_Service.wsdl] /language:CS

You can get information on this and other options by typing wsdl /? at the
command prompt.

Using the VS .NET IDE

1. Select Project, Add Web Reference.

2. In the Add Web Reference dialog, type the path to the local copy of
the [Java class name]_Service.wsdl file in the Address combo box. Then,
press arrow button next to the combo box.

3. Click the Add Reference button.

This produces a file in the project language and automatically includes the
file in your project.

3 Verification it Works
At this point in time, you should be able to use the proxy you generated in
the Create the proxy step. Simply use the proxy as you would any other .NET
class. You can see what the environment calls the proxy by viewing the
information in the VS .NET IDE Class View or by looking at the generated
proxy.

4 Copyright
The material in this article is protected by Copyright (© 2001) by Microsoft
Corporation. All rights reserved. Microsoft offers no warranties, express or
implied, as to the suitability of this material for use.


"George T. Bone" <webser...@lycos.com> wrote in message
news:134c3016.01091...@posting.google.com...

George T. Bone

unread,
Sep 24, 2001, 4:55:29 PM9/24/01
to
Hi Scott,
Thanks for the help. I'll try your suggestion.
However, to set straight what I tried...
1) I set out to try to create a complex WSDL structure passed to a
VB7.Net
WebApplication as a parameter to a [WSDL-defined] function. The
idea was to
_early bind_ to a function with a "structure" [aka complex type in
WSDL] as
a parameter. The key I was after was an early binding to a complex
structure
in VB.Net via Web Reference.

2) Initially I tried to use straight WSDL created via MS SOAP Toolkit
& a few
VB6 projects, then hand edited to point to a different location -
very low
risk IMHO. This did not work.

3) Next I tried a VB7.Net Web Service with a complex type.
I did a Web Reference with early binding.
This was essentially what I wanted, except I wanted the WSDL to
reference a
Java Applet through a difference non-IIS Webserver [Jigsaw].

4) I used XMLNotepad to open the aspx (with a WSDL "get") as follows:
http://mypc/complex/Service1.asmx?WSDL

5) I saved the WSDL and then edited it to change the service location
reference
to point to a Java servlet on a JigSaw Webserver [port 50] as
follows:
http://mypc:50/servlet/myjavaws

Then I tried to Add Web Reference - which failed to produce much of
any result. No early binding.

Odd, I tried this with a non-complex function and it worked fine...!
Explain that, my friend.

Thanks Scott,
George T. Bone

"Scott Seely" <sse...@nospam.microsoft.com> wrote in message news:<uFO6$XsQBHA.476@tkmsftngp04>...

George T. Bone

unread,
Sep 28, 2001, 1:24:09 PM9/28/01
to
Hello msdn.webservices ng readers.
The following is a synopsis of the solution to complextypes in .Net
After many emails back & forth with Scott Seely I feel compelled to post
this information so anyone else looking may find it useful.

The main problem was my approach of using XMLnotepad to open a URL to a
VB7.Net WebService [http://mypc/WebService1/Service1.asmx?WSDL] and save
the result. XMLnotepad added blank namespaces in numerous places.
For example:
<types xmlns="">
<message xmlns="" name="LearnSoapIn">
<portType xmlns="" name="Service1Soap">
<binding xmlns="" name="Service1Soap" type="s0:Service1Soap">
<service xmlns="" name="Service1">

Scott removed these and returned the corrected WSDL file, then suggested
I use VS7's WSDL.exe [search msdn for wsdl.exe] to create a "proxy DLL"
from the WSDL: this "proxy DLL" provides the early binding to structures,
aka complex types, through an object with public member data named after
the components of the complex type. WSDL.exe also created another object
that calls Invoke to serialize the object/structure data into a soap
message it sends to the URL specified in the WSDL's service location:
<service name="Service1">
<port name="Service1Soap" binding="s0:Service1Soap">
<soap:address location="http://mypc:42/webservice/webservicej1"/>
</port>
</service>

NOTE: I had changed:
<soap:address location="http://mypc/WebService1/Service1.asmx"/>
to:
<soap:address location="http://mypc:42/webservice/webservice1"/>
so that when it ran it referenced my JigSaw server [:42] and my Java
Servlet [webservice1] instead of the skeleton VB project.

I created a true VB7.Net WebService with a structure and a single
skeleton function which took this structure as a parameter. Here is the
structure and skeleton code in the V7 WebService1 project:
Structure LearnStruct
Public Course As String
Public Teacher As String
Public CreditHours As Integer
Public IsFree As Boolean
End Structure

<WebMethod(Description:="This method registers a course.")> _
Public Function Learn(ByVal WhatClass As LearnStruct) As Boolean
...
End Function

Using the Visual Studio.NET Command Prompt, I cd'ed to my WSDL directory
and ran:
wsdl.exe webservicej1.wsdl /language=VB
It creates a Service1.vb file that can be used to create a VB DLL.
The VB DLL can then be referenced in a VS.Net WebApplication to provide
early binding to a complex type, and in this case that sends the soap
message to a Java servlet on a Java server [JigSaw]. It even provides
an asynchronous set of methods!

This is really cool! The odd part is that the WSDL is not needed
afterwards. I would have thought there would be a simpler way to do this
that would be dynamically driven by the WSDL. I suppose we'll have to
wait for VB8 to get dynamic early binding... eh Scott?

Special thanks to Scott Seely for his instant response and perfect help.
I suggest we all go buy his book <smile>

<Seinfeld> just call me George, or beta yet T-Bone. </Seinfeld>
D

webser...@lycos.com (George T. Bone) wrote in message news:<134c3016.01092...@posting.google.com>...

ken h

unread,
Oct 1, 2001, 3:54:02 AM10/1/01
to
I really appreciate this article written by SCOTT!!!

After I edited WSDL file like this article mentioned,
wsdl.exe did not show error message any more.

By the way, some one knows the way to building the Java
client from WSDL created VS.NET?

The proxygen in WSTK 2.4 shows error message every time.
I don't know how to edit WSDL file correctly.


Thanks,
kenji


"Scott Seely" <sse...@nospam.microsoft.com> wrote in
message news:uFO6$XsQBHA.476@tkmsftngp04...

> &#12461; Windows NT 4.0 (SP 6), 2000 (SP1), XP.
>
> &#12461; IIS version 4.0, 5.0, or 6.0
>
> &#12461; .NET Framework SDK

> &#12461; Visual Basic: wsdl [Java class
name_Service.wsdl] /language:VB
>
> &#12461; JavaScript: wsdl [Java class
name_Service.wsdl] /language:JS
>
> &#12461; C#: wsdl [Java class

(&#12453; 2001) by Microsoft

Foghorn Leghorn

unread,
Oct 1, 2001, 9:57:50 AM10/1/01
to

<soap:address location="http://mypc:42/webservice/webservicej1"/>


so that when it ran it referenced my JigSaw server [:42] and my Java

Servlet [webservicej1] instead of the skeleton VB project.

webser...@lycos.com (George T. Bone) wrote in message news:<134c3016.01092...@posting.google.com>...

Scott Seely

unread,
Oct 3, 2001, 8:20:47 PM10/3/01
to
I assume that you have not decorated VS .NET code with attributes. In other
words, your taking the default stuff that VS.net provides.

In a word yes we have an article on that as well. It won't be posted for
awhile on the knowledge base so here it is:

1 How To: Integrate Apache SOAP 2.2 Client with a basic .NET XML Web
Service
This article describes how to integrate an Apache SOAP 2.2 client with an
ASP .NET based XML Web Service. This assumes that the ASP .NET server-side
component exposes the Web Method with the WebMethod attribute and does
nothing more than provide a namespace for the Web Service itself.

Requirements

The following items describe the recommended hardware, software, network
infrastructure, skills and knowledge and service packs you will need.

· Java JDK 1.3

· Apache SOAP 2.2

Prior Knowledge required

You will need to know how to setup how to setup the Apache SOAP 2.2
libraries. You can find information on how to do this with the downloads for
these products. Links to the home pages for the various items are located at
the bottom of the article. You will also need to be familiar with Java. When
using complex types in the SOAP interfaces, it will help to understand
JavaBean technology as well.

You will also need some familiarity with Web Service Description Language
(WSDL) files when creating the various Java classes. Additionally, you
should be familiar with the SAX XML parsing model.

1 Assumptions about .NET XML Web Service
This article assumes that your .NET Web Service looks something like this:

C#:

public class SimpleService : System.Web.Services.WebService

{

public SimpleService() {

}

[WebMethod]

public string echoString(string inputString) {

if ( inputString == null ) {

return "Input string is null";

}

return inputString;

}

}

Visual Basic .NET:

Public Class SimpleService

Inherits System.Web.Services.WebService

Public Sub New()

MyBase.New()

End Sub

<WebMethod()> Public Function echoString( _

ByVal inputString As String) As String

echoString = inputString

End Function

End Class

These declarations tell the .NET runtime to not expect any encoding
information and to interpret the messages as document/literal types. That
is, the element names mean something and the server is responsible for
knowing what data types are being passed in. The Apache SOAP Toolkit was
designed as an RPC mechanism, not a document exchange mechanism. As a
result, we have to modify the plumbing a bit to get everything working
correctly. To do this, we need to do the following:

1. Write a Java proxy for the .NET endpoint.

2. Create our own class that generates the SOAP message Body element.

3. Create our own class that parses the SOAP response.

2 The Java Proxy
The IBM Web Services Toolkit can produce proxies. Due to the amount of work
you need to do once the proxy is generated, it will most likely be easier to
write the proxy by hand. Beyond that, you need to write functions that mimic
the signatures in the WSDL of the operations associated with the portType
you are connecting to. For example, the echoString function signature looks
like this:

public synchronized String echoString( String inputString )

throws SOAPException

This will allow users of the proxy to instantiate the proxy and call
functions, while only worrying about handling SOAP Faults. The basic flow of
the proxy works like this:

1. Check that the URL has been set.

2. Prepare the message.

3. Send the message.

4. Parse the response.

Because of the way the Apache SOAP 2.2 classes encode message, we need to
override the piece that builds the body as well as the parts that interpret
the response. We need to change the way the response is handled because the
changes to Apache go outside its original RPC design. The full code to call
echoString would look like this:

public synchronized String echoString( String inputString )

throws SOAPException {

String retval = "";

if (url == null) {

throw new SOAPException(Constants.FAULT_CODE_CLIENT,

"A URL must be specified via " +

"SoapBuildersExSoapProxy.setEndPoint(URL).");

}

// Instantiate the message and the envelope.

// The message sends the envelope and gets

// the response.

Message message = new Message();

Envelope env = new Envelope();

DataHandler soapMsg = null;

// Get this from the soapAction attribute on the

// soap:operation element found within the SOAP

// binding information in the WSDL

String SOAPActionURI = "http://tempuri.org/echoString";

MessageBody theBody = new MessageBody();

// Set the argument.

theBody.echoString = inputString;

// Replace the default body with our own.

env.setBody( theBody );

message.send( getEndPoint(), SOAPActionURI, env );

try{

// Because the Body.unmarshall handler is static,

// we can't replace the basic machinery easily.

// Instead, we have to get and parse the

// message on our own.

soapMsg = message.receive();

XMLReader xr = XMLReaderFactory.createXMLReader(

"org.apache.xerces.parsers.SAXParser");

ClientHandler ch = new ClientHandler();

ch.setElementToSearchFor("echoStringResult");

// Set the ContentHandler...

xr.setContentHandler( ch );

// Parse the file...

xr.parse( new InputSource(

new StringReader( soapMsg.getContent().toString() ) ) );

// At this point, the result has been parsed and stored

// within the ClientHandler instance.

retval = ch.getResult();

} catch ( Exception e ) {

// We need to do something with the exception.

// Here, we print out the exception to the console.

System.out.println( "***Exception***: " + e.toString() );

}

return retval;

}

This basic form should work regardless if the actual argument is a simple
type like a string or a complex type like an array. The hard part comes in
creating the Body. You need to do the serialization by hand.

3 Overriding the Body Serialization
Apache SOAP uses a class called Body to serialize and deserialize SOAP
messages. It does so with two methods: marshall and unmarshall. marshall is
an instance method and unmarshall is a static class method. Because of the
structure of the Apache SOAP library and the way we are using it, we cannot
inherit from Body and expect our own version of unmarshall to be called.
Fortunately, we can replace marshall and change how we serialize the SOAP
Body element. To correctly serialize the echoString method, just provide
your own, extended version of Body. Depending on how many methods you have,
you can either create one version of a class that extends Body per method or
you can have marshall pick the correct code based on other information. That
decision is up to you.

Assuming that you only serialize one method call in the derived class, here
is what the class needs to have:

1. A way to set the data being serialized.

2. Knowledge of how to write the XML so that it is formatted correctly
for the ASP .NET endpoint.

Because the ASP .NET endpoint uses document/literal encoding, you will only
need to write out the following information:

1. Body element

2. Method name and corresponding namespace.

3. Arguments passed into the method.

For the echoString example, the class looks like this:

import java.io.*;

import org.apache.soap.util.*;

import org.apache.soap.*;

import org.apache.soap.util.xml.*;

import org.apache.soap.rpc.SOAPContext;

public class MessageBody extends Body

{

public String echoString;

public void marshall(String inScopeEncStyle,

Writer sink,

NSStack nsStack,

XMLJavaMappingRegistry xjmr,

SOAPContext ctx)

throws IllegalArgumentException, IOException

{

// Set the Body element

String soapEnvNSPrefix = "SOAP-ENV";

sink.write('<' + soapEnvNSPrefix + ':'

+ Constants.ELEM_BODY + '>' + StringUtils.lineSeparator);

// Write out the method name and related argument(s)

sink.write("<echoString xmlns=\"http://tempuri.org/\">" +

"<inputString>" + echoString +

"</inputString></echoString>" );

// Close the SOAP Body

sink.write("</" + soapEnvNSPrefix + ':' +

Constants.ELEM_BODY + '>' + StringUtils.lineSeparator);

nsStack.popScope();

}

}

Now that we can send the message, we need to be able to read the response.
To do this, we need a class that will be called by the SAX parser.

4 Parsing the response
When the message goes out and then comes back, we can get at the entire SOAP
response. This part comes into play within the code in the example proxy's
echoString try/catch block. This example ClientHandler attempts to be a
general purpose class that can grab any single element response. Users of
the class should be able to use the class as is. If the value is really a
boolean, date, or numeric type, you should be able to do the conversion
after retrieving the result. More complex types will need more complex
implementations.

To retrieve simple values, this should be all you need:

import org.xml.sax.helpers.*;

import org.xml.sax.*;

public class ClientHandler extends DefaultHandler {

private String result = "";

private String elementToSearchFor = "";

private boolean foundResult = false;

public ClientHandler() {

}

public String getResult(){

return result;

}

public void setElementToSearchFor( String elemName ) {

elementToSearchFor = elemName;

}

public String getElementToSearchFor() {

return elementToSearchFor;

}

// Override methods of the DefaultHandler class

// to gain notification of SAX Events.

//

// See org.xml.sax.ContentHandler for all available events.

//

public void startElement( String namespaceURI,

String localName,

String qName,

Attributes attr ) throws SAXException {

if ( foundResult == false ) {

foundResult = (localName.compareTo(

elementToSearchFor ) == 0);

}

}

public void characters( char[] ch, int start, int length )

throws SAXException {

if ( foundResult ) {

// Read all the data in

result = String.valueOf( ch, start, length );

foundResult = false;

}

}

}

In the above class, you call getResult to get the single element result.
Modify the code as appropriate for complex types and arrays.

5 Pitfalls
Overriding all of this can be time consuming and error-prone. Make sure to
test your proxy that it can handle whatever the ASP .NET XML Web Service
might return to you.

6 Additional resources
· Java JDK home page

· Apache SOAP home page

· Writing or using Custom Apache Serializers/Deserializers

· At Your Service: Interoperability Testing

· Original post to soapbuilders, including the source as an
attachment.

7 Copyright
The material in this article is protected by Copyright (© 2001) by Microsoft


Corporation. All rights reserved. Microsoft offers no warranties, express or
implied, as to the suitability of this material for use.

The material listed in the following section has been added by readers of
the document. These comments have not been validated by Microsoft
Corporation, nor has their suitability, accuracy, or effectiveness been
tested. The statements below are the opinions of the posters and not those
of Microsoft Corporation.


"ken h" <ken_...@hotmail.com> wrote in message
news:060b01c14a4e$3ca7d0e0$a5e62ecf@tkmsftngxa07...

ken h.

unread,
Oct 4, 2001, 10:58:32 PM10/4/01
to
Thank you for the reply!!
I'm really appreciate.

Unfortunatelly, I'm not familiar writh WSDL.

So, in a word, your article says,
"It is not able to produce proxies from WSDL file
generated by VS.NET, by using proxygen.bat in WSTK2.4.
"?

Can "proxyge.bat" generate japa-proxy from WSDL file
automatically, and easily???

I prefer easy-way.


Thanks,
Kenji

>.
>

ken h.

unread,
Oct 17, 2001, 8:03:22 AM10/17/01
to
hi, I succeeded in accessing .NET Web Service from
Japa client.

So, I post some experience.

1. .NET side
implemtn echoString method
implement RPC instead of document type for SOAP
change namespace something from http://tempuri.org

2. Java side
using AXIS
source code is the following;

import org.apache.axis.client.ServiceClient;
import org.apache.axis.message.RPCParam;

public class TestClient {
public static void main(String args[]) {
try {
String endpoint = "http://machin-
name/java3/Service1.asmx";
ServiceClient client = new ServiceClient
(endpoint);

String res = (String)client.invoke
("http://www.scs.co.jp", "echoString",
new Object [] {
new RPCParam("inputString", "Saitoh Yuta") });

System.out.println("Send 'Hello!' , Get '" +
res + "'");
} catch(Exception e) {
System.out.println("error:" + e.toString());
}
}
}

that's all!

so easy?

thanks,
ken

>.
>

0 new messages