48

In WSDL file a function can return a Type or an Element. I have used only custom types as a results so far. However, I wonder when the Element should be more appropriate than the Type? What is the difference between them?

Is there any difference between

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" element="tns:Person"></wsdl:part>
</wsdl:message>

and

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" type="tns:Person"></wsdl:part>
</wsdl:message>

from a Client perspective (application that uses the web service)?

The above question, as skaffman pointed, leads to a another question. What is the difference between

<xs:element name="Person" ... >
 ...
</xs:element>

and

<xs:complexType name="Person">
   ...
</xs:complexType>

?

user3399000
  • 353
  • 3
  • 18
czuk
  • 6,218
  • 10
  • 36
  • 47

4 Answers4

17

There's more to it than that.

There is some ambiguity in the standards that can cause interoperability problems. You have to use type or element depending on whether you're using a Document-based service or an RPC-based service.

There are also ambiguities. If you say

<wsdl:message name="message1" type="ns:type1"/>

Then you've said that the content of the message must validate against type "ns:type1". But you've said nothing about the element that contains the content. What namespace will it be in?

Refer to the WS-I Basic Profile for some rules on this.


There's been some discussion in the comments about "document/literal" vs. "document/literal/wrapped". Here's my take.

I just created a web service. Here's the whole thing:

using System.Web.Services;

namespace WebService1
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class SimpleMathService : WebService
    {
        [WebMethod]
        public int Add(int a, int b)
        {
            return a + b;
        }

        [WebMethod]
        public int Multiply(int a, int b)
        {
            return a*b;
        }
    }
}

I won't post the entire WSDL, but here are the "good parts":

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" 
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
     targetNamespace="http://tempuri.org/" xmlns:tns="http://tempuri.org/" >
    <wsdl:types>
        <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
            <s:element name="Add">
                <s:complexType>
                    <s:sequence>
                        <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int"/>
                        <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int"/>
                    </s:sequence>
                </s:complexType>
            </s:element>
            <s:element name="AddResponse">
                <s:complexType>
                    <s:sequence>
                        <s:element minOccurs="1" maxOccurs="1" 
                           name="AddResult" type="s:int"/>
                    </s:sequence>
                </s:complexType>
            </s:element>
            <s:element name="int" type="s:int"/>
        </s:schema>
    </wsdl:types>
    <wsdl:message name="AddSoapIn">
        <wsdl:part name="parameters" element="tns:Add"/>
    </wsdl:message>
    <wsdl:message name="AddSoapOut">
        <wsdl:part name="parameters" element="tns:AddResponse"/>
    </wsdl:message>
    <wsdl:portType name="SimpleMathServiceSoap">
        <wsdl:operation name="Add">
            <wsdl:input message="tns:AddSoapIn"/>
            <wsdl:output message="tns:AddSoapOut"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="SimpleMathServiceSoap" type="tns:SimpleMathServiceSoap">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="Add">
            <soap:operation soapAction="http://tempuri.org/Add" style="document"/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="SimpleMathService">
        <wsdl:port name="SimpleMathServiceSoap" binding="tns:SimpleMathServiceSoap">
            <soap:address location="http://localhost:5305/SimpleMathService.asmx"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

Note how the word "wrapped" does not appear. What IBM in their document is calling "document/literal/wrapped" is simply "document/literal", that happens to use a single message part, that happens to have a name derived from the name of the service, and that happens to refer to an element, and which happens to contain both the parameters to the operation.

There's nothing magical here, there's nothing non standard here.

In many standards organizations companies wind up taking sides. In the case of SOAP, we've got the "RPC side" and the "Document side". RPC is more familiar to many people - it maps one to one with a function call. Document is less familiar, and requires that you actually think in terms of simple XML. Perhaps IBM was on the RPC side, I don't know.


I have now finished the IBM document, Which style of WSDL. The summary is:

Summary

There are four binding styles (there are really five, but document/encoded is meaningless). While each style has its place, under most situations the best style is document/literal wrapped.


I also want to react to the places in the document where it discusses the level of difficulty in dispatching, based on whether the operation name is present in the message. This is a non-issue. If you read the document, you'll note that it never discusses anything in the <binding> section. The solution to the "no operation name" problem is there.

<wsdl:binding name="SimpleMathServiceSoap" type="tns:SimpleMathServiceSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Add">
        <soap:operation soapAction="http://tempuri.org/Add" style="document"/>

The soapAction is sent in the HTTP headers of the request, and can be used for dispatching:

POST /SimpleMathService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Add"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Add xmlns="http://tempuri.org/">
      <a>int</a>
      <b>int</b>
    </Add>
  </soap:Body>
</soap:Envelope>
Community
  • 1
  • 1
John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • So, if I use a RPC-based service all my functions should return a Schema element? – czuk Jul 23 '09 at 17:10
  • I don't know. I don't use them. I find them problematic. I always use document/literal. – John Saunders Jul 23 '09 at 17:16
  • For document/literal the operation name is lost. I have a couple of functions with the same set of arguments so I cannot use document/literal. Despite this, have you ever used an Schema element as a function result? – czuk Jul 23 '09 at 17:28
  • I have no idea why you think you can't use document/literal. Got an example? – John Saunders Jul 23 '09 at 18:56
  • Let's say I have two functions int add(int a, int b) and int multiply(int a, int b). When client runs any of those two methods the same SOAP message is generated: [SOAP-ENV:Body>[a>1[/a>[b>2[/b>[/SOAP-ENV:Body> (I replaced all > with [ because they disappeared). The operation name is lost. For both operation the client will receive the same result because each time the first operation will be executed. So I could use document/literal only if I change the interface by merging the functions or discriminating their arguments. – czuk Jul 23 '09 at 19:34
  • No way. They'll be wrapped by an element based on the operation name. How'd you create these services? ASMX or WCF? Either way, I'll try it right now and show you. Maybe start a new question on this so we're not doing comments. – John Saunders Jul 23 '09 at 19:45
  • Just tried it. No problem. `12`. (Hint: surround inline code with ``) – John Saunders Jul 23 '09 at 19:53
  • 1
    That's strange. Are you sure you are using document/literal? According to this article http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/ Listing 5 this is a rpc/literal message. – czuk Jul 23 '09 at 20:03
  • They gave a bad example. Mine has one part named parameters, which is an element named "Add", which is q sequence of x and y. – John Saunders Jul 23 '09 at 20:20
  • 1
    I see. Read on. Microsoft uses what they call "document/literal wrapped", as though there were something wrong with it. They then come close to lying when they say it's necessary to make an "educated guess". Nonsense. The message has a part which is an element which is of a type defined in the schema. The operation uses the message. No need to guess. – John Saunders Jul 23 '09 at 20:25
  • Ok, but "document/literal wrapped" is not the same as "document/literal". I thought you were talking about the second one. You can read in this article, that one of the weakness of the "document/literal" is "The operation name in the SOAP message is lost. Without the name, dispatching can be difficult, and sometimes impossible." – czuk Jul 23 '09 at 20:33
  • Thank you for the long explanation. As I understand C# wrap the messages for document/literal by default, so there is no problem with the operation name. The situation is different in PHP. When using SoapClient the operation name is lost as it is stated in the referred article. My conclusion is that, document/literal in C# is in fact wrapped document/literal. In turn in PHP there is no difference. How in other languages? I do not know that. – czuk Jul 24 '09 at 06:42
10

Which one you use depends on the schema to which it is referring. If tns:Person is defined in the schema as:

<xs:element name="Person" ... >
 ...
</xs:element>

Then you use

<wsdl:part name="parameters" element="tns:Person">

If, on the other hand, the schema is defined as

<xs:complexType name="Person">
   ...
</xs:complexType>

then you use

<wsdl:part name="parameters" type="tns:Person">

So the question is really what's the difference between Schema elements, and Schema types.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 1
    Yes exactly, I would like to know when should I create a Schema type and when Schema element. Or, maybe in this context there is no difference? – czuk Jul 23 '09 at 17:06
  • 1
    You'd do better not to create either on your own until you know this stuff a bit better. In the meantime, depend on auto-generated WSDL and schema files. – John Saunders Jul 23 '09 at 17:07
2

I cannot comment on the WSDL part of the question, but I'll answer the XML Schema part.

<xs:complexType> defines a type, which describes content of an element, without describing the element itself (i.e. its name). <xs:element> describes an element (specifically its name), but not its type. However, <xs:element> always references the type for the content of the element it describes. This can be a reference to an existing type (including, but not limited to, <xs:complexType> - it can also be <xs:simpleType>, for example) definition elsewhere in the schema, or an inline <xs:complexType> definition:

<xs:element name="foo">
   <xs:complexType>
      ...
   </xs:complexType>
</xs:element>

Since the above construct is so common, you can actually omit <xs:complexType> entirely, and it will be implied.

As for whether you should always define types separately and then reference them in element declarations, or whether you should prefer defining element types inline within element declarations, it is a matter of style.

Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • According to skaffman a `complexType` can be named. So, what is the difference between naming the `complexType` and wrapping the type with an `element`? – czuk Jul 24 '09 at 06:55
  • 1
    If you name it, you can apply it to several different element declarations, and/or derive other types from it. So you can have complexType Person, derive complexType Employee from it by extension (adding more child elements to describe attributes), and then assign those types to elements "Person" and "Employee", for example. – Pavel Minaev Jul 24 '09 at 17:41
0
<xs:element name="person" type="persontype"/>

<xs:complexType name="persontype">
  <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

the <element> of type attribute is referring <complexType> of name attribute.


<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" element="tns:person"></wsdl:part>
</wsdl:message>

and

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" type="tns:person"></wsdl:part>
</wsdl:message>
  • <part> parameter associates with a concrete type defined in the <types> container element. and <part> can refer to either <complexType> by type attribute or <element> by element attribute as shown above.
  • It can be either <complexType> or <portType> or any, which are referred by type attribute.
Premraj
  • 72,055
  • 26
  • 237
  • 180