2
Web Services Description Language (WSDL)
A WSDL file enjoys the look and
feel of an XML document, since it actually is an XML document. Therefore, all
the rules of XML apply to it too.
This chapter is an extension of
the previous chapter. Hence, the asmx file remains the same. We have displayed
the asmx file below. All that the file contains is, a single function named
abc.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System.Web.Services;
public class zzz
{
[WebMethod]
public int abc(int i, int j)
{
return i + j;
}
}
Create a new folder named aaa,
and run the following command in it :
>Wsdl http://localhost/a.asmx?WSDL
This creates a file called
zzz.cs. Compile the C# file to a dll, using the following csc command:
Csc /t:library zzz.cs
Next, create one more program
called a.cs, in the folder aaa.
a.cs
public class aaa
{
public static void Main()
{
zzz a = new zzz();
int b;
b = a.abc(10,21);
System.Console.WriteLine(b);
}
}
Compile it using Csc a.cs
/r:zzz.dll . On running the exe file a, an output of 31 is obtained. In a
single stroke, the WSDL program has effortlessly replicated all that we had
achieved with so much hard work in the previous chapter. In the zzz.cs file, it
creates a class named zzz, which includes one function called abc. This
function contains code, which calls the abc function from the file a.asmx.
Let us take a sneak preview of
the code generated by the WSDL program, and discover what goes on behind the scenes.
zzz.cs
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Runtime Version: 1.0.2914.16
//
// Changes to this file may cause incorrect behavior and will be
lost if
// the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
//
// This source code was auto-generated by wsdl,
Version=1.0.2914.16.
//
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.Web.Services;
[System.Web.Services.WebServiceBindingAttribute(Name="zzzSoap",
Namespace="http://tempuri.org/")]
public class zzz : System.Web.Services.Protocols.SoapHttpClientProtocol
{
[System.Diagnostics.DebuggerStepThroughAttribute()]
public zzz() {
this.Url = "http://localhost/a.asmx";
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/abc",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public int abc(int i,
int j) {
object[] results = this.Invoke("abc", new object[] {
i, j});
return ((int)(results[0]));
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public System.IAsyncResult Beginabc(int i, int j,
System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("abc", new object[] {
i,j}, callback, asyncState);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public int Endabc(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((int)(results[0]));
}
}
The cat is out of the bag! While
attempting to learn about web services, we had made use of this approach. After
understanding the process of calling code from a remote server, we have
displaced the irrelevant parts from the program, thus, condensing and simplifying
it, before finally presenting it to you. The code that is displayed above, was
used in the previous chapter, while elucidating the basics of web services.
Let us probe a little deeper to
figure out the program generated by the WSDL program. The parameter supplied to
the WSDL command is http://localhost/a.asmx?WSDL.
There is an unyielding rule that
whenever any program generates a file, the opening lines in the file, must be a
set of comments. So, the file zzz.cs hits the road with these mandatory
comments. Its the 'using' statements for the namespaces, which follow these
comments.
The class zzz has the attribute
of WebServiceBindingAttribute, which we encounter for the first time. The
responsibility of this attribute is to denote a class containing one or more
WebService methods. The 'name' property in the attribute is the name of the
binding given in the format of a colon, followed by the name of the class, and
finally, followed by the word 'soap'. However, this is only optional.
The class zzz is derived from
the SoapHttpClientProtocol class. The class is known as zzz, since the file is
named zzz.cs; furthermore, the file is named zzz.cs, because the WebService
directive in the asmx file is initialized to zzz.
All the functions, together with
the constructor, contain the attribute named DebuggerStepThroughAttribute. This
attribute, as the name itself suggests, is brought into play for diagnostics or
for the purpose of debugging. It is also optional. In the constructor, the Url
property is initialized to the asmx file, accompanied by the server name on
which it is located.
Not only does the function abc
in zzz.cs, have the same return value as the function in the asmx file, but
also has the same parameter names. The Invoke function is called in the same
manner, as was done previously.
As was pointed out earlier, the
code in the previous chapter was cut, copied and pasted from the proxy
generated by the WSDL program.
There are two more functions in
the .cs file named Beginabc and Endabc. These two functions were not
encountered earlier, since they are utilized only when the abc function is to
be executed in an asynchronous manner.
When the call is synchronous, as
was the case in the previous chapter, the program execution pauses and ceases
until the call ends. On the other hand, in an asynchronous execution, the
function gets executed and there is a wait, but when it is all done with, the
Endabc function gets called. The mechanism of the asynchronous execution shall
be touched upon a little later in the book. You would appreciate that the
program-generated code can never look appealing!!
Let us now understand the
parameter passed to the WSDL program. Enter the same url of http://localhost/a.asmx?WSDL in a browser.
On doing so, an XML file gets
displayed in the browser window. Create
a new folder wsdl and save the contents to a text file named aa.wsdl within it.
Then, enter the following command:
Wsdl aa.wsdl
The command generates the same
zzz.cs file, which when compiled to a dll, generates the same output. Let us
now unveil the magic of the aa.wsdl file.
aa.wsdl
<?xml version="1.0" encoding="utf-8"?>
<definitions
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s0="http://tempuri.org/"
targetNamespace="http://tempuri.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">
<s:element name="abc">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="i" type="s:int" />
<s:element minOccurs="1" maxOccurs="1"
name="j" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="abcResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="abcResult" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="int" type="s:int" />
</s:schema>
</types>
<message name="abcSoapIn">
<part name="parameters" element="s0:abc"
/>
</message>
<message name="abcSoapOut">
<part name="parameters"
element="s0:abcResponse" />
</message>
<message name="abcHttpGetIn">
<part name="i" type="s:string" />
<part name="j" type="s:string" />
</message>
<message name="abcHttpGetOut">
<part name="Body" element="s0:int" />
</message>
<message name="abcHttpPostIn">
<part name="i" type="s:string" />
<part name="j" type="s:string" />
</message>
<message name="abcHttpPostOut">
<part name="Body" element="s0:int" />
</message>
<portType name="zzzSoap">
<operation name="abc">
<input message="s0:abcSoapIn" />
<output message="s0:abcSoapOut" />
</operation>
</portType>
<portType name="zzzHttpGet">
<operation name="abc">
<input message="s0:abcHttpGetIn" />
<output message="s0:abcHttpGetOut" />
</operation>
</portType>
<portType name="zzzHttpPost">
<operation name="abc">
<input message="s0:abcHttpPostIn" />
<output message="s0:abcHttpPostOut" />
</operation>
</portType>
<binding name="zzzSoap"
type="s0:zzzSoap">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="abc">
<soap:operation soapAction="http://tempuri.org/abc"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<binding name="zzzHttpGet"
type="s0:zzzHttpGet">
<http:binding verb="GET" />
<operation name="abc">
<http:operation location="/abc" />
<input>
<http:urlEncoded />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
<binding name="zzzHttpPost"
type="s0:zzzHttpPost">
<http:binding verb="POST" />
<operation name="abc">
<http:operation location="/abc" />
<input>
<mime:content
type="application/x-www-form-urlencoded" />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
<service name="zzz">
<port name="zzzSoap"
binding="s0:zzzSoap">
<soap:address location="http://localhost/a.asmx"
/>
</port>
<port name="zzzHttpGet"
binding="s0:zzzHttpGet">
<http:address location="http://localhost/a.asmx"
/>
</port>
<port name="zzzHttpPost"
binding="s0:zzzHttpPost">
<http:address location="http://localhost/a.asmx"
/>
</port>
</service>
</definitions>
The hitch that occurs while
attempting to comprehend the above xml file, can be attributed to the
gargantuan size of the file. So, we have stripped it of all superfluous
portions, and arrived at a compact file, as is revealed below:
aa.wsdl
<?xml version="1.0" encoding="utf-8"?>
<definitions
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s0="http://tempuri.org/" targetNamespace="http://tempuri.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">
<s:element name="abc">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="i" type="s:int" />
<s:element minOccurs="1" maxOccurs="1"
name="j" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="abcResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="abcResult" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</types>
<message name="abcSoapIn">
<part name="parameters" element="s0:abc"
/>
</message>
<message name="abcSoapOut">
<part name="parameters" element="s0:abcResponse"
/>
</message>
<portType name="zzzSoap">
<operation name="abc">
<input message="s0:abcSoapIn" />
<output message="s0:abcSoapOut" />
</operation>
</portType>
<binding name="zzzSoap1"
type="s0:zzzSoap">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="abc">
<soap:operation soapAction="http://tempuri.org/abc"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="zzz">
<port name="zzzSoap2"
binding="s0:zzzSoap1">
<soap:address location="http://localhost/a.asmx"
/>
</port>
</service>
</definitions>
Akin to an XML document, which
mandates the presence of an xml declaration with the version attribute on the
first line, the WSDL file too has the need for the same. However, the encoding
attribute is optional. Since every XML document has to have a root element or a
starting tag, the WSDL also has one. The tag is called 'definitions'.
The tag named 'definitions'
cannot be altered to anything else. Moreover, there cannot be more than one
occurrence of it, since there can only be just one, and only one root tag. The
root element can possess a large number of namespace declarations, with the use
of the attribute of xmlns.
People have penned down volumes
on the topic of 'namespaces', right from the time that programming came into
vogue. However at the end of the day, all that a namespace is worthy of is
that, it ensures that tags created by one, do not clash with the tags created
by the other. That is all there is to namespaces, i.e. providing each tag with
its own space, by prefacing each of them with its namespace name. Altogether, five namespaces are created in
the root tag.
<definitions
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s0="http://tempuri.org/" targetNamespace="http://tempuri.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
The first namespace is named as
s. It points to a URI that represents XML Schemas. XML Schemas are merely XML
specifications that ascertain whether the XML document follows the laid down
specifications or not. There is more to it than just specifications, but for
the moment, it would suffice to say that the rules are prescribed in the
specifications. Thus, any element that starts with the namespace 's' followed
by a colon, belongs to the XML Schema namespace. Normally, the namespace prefix
used is 'xsd', but the name of the prefix is not as significant as its value.
The elements beginning with
'soap' and 'soapenc' belong to the SOAP namespace. Here, s0 is the namespace
used for the entities, which are created to represent our asmx file. One
essential point to be taken into account is that, the wsdl file is created by IIS
from the asmx file. Therefore, everything in this file represents the asmx
file. Also, it is the wsdl file and not the asmx file, which is used by the
WSDL program to create the proxy. The targetNamespace also points to the soap
world. The default namespace specified by the xmlns attribute, applies to all
those elements that are without a namespace prefix.
The root tag of 'definitions'
contains six different types of child elements. On the top of the list is
'types', which renders assistance in creating types and elements. A 'type' is
akin to a data type, while an 'element' is analogous to a tag. In the SOAP
payload, you may have noticed the use of elements, such as abc and abcResponse.
Now, someone somewhere has to create these elements. The WSDL file is
designated to accomplish this task.
The child element of 'types'
begins with the schema element from the XML Schema namespace, as it is prefaced
with the namespace prefix s. This schema element is the root tag for any schema
file. The targetNamespace attribute is also mentioned in the definitions
element.
<types>
<s:schema attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">
All elements in this schema
belong to the targetNamespace URI, which is tempuri.org. The elementFormDefault
attribute can have only two values, viz. qualified and unqualified, with the
default value being 'unqualified'. The value qualified merely signifies that
all elements from the targetNamespace must be qualified with the namespace
prefix. The attributeFormDefault endorses a concept similar to that of the
attributes. What follows thereafter, upto the closing schema element, is merely
an XML Schema document.
To all those of you who have
perused our book on XML Schemas, some of these explanations may appear
monotonously reiterative, but a second explanation would surely not peeve
anyone. For those of you who find it challenging to grapple with XML Schemas,
there is a silver lining, as we shall endeavor to bring in the entire update to
you shortly.
The SOAP payload reflects an
element called abc. Let us perceive as to how and where the element has been
created in the file.
To create an element, the 'name'
attribute is used, and then assigned a value. Once the element is created, a
type is specified for it.
<s:element name="abc">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="i" type="s:int" />
<s:element minOccurs="1" maxOccurs="1"
name="j" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
The trouble with an element is
that, it can either contain other elements or only content and attributes. This
element has been assigned a complexType, but if it were a simple element, we
could have used simpleType in lieu. The next task is to define the complexity
of the type. There is a sequence tag that maintains an order. This tag in turn,
defines two more elements named i and j.
The elements i and j are child
elements within the abc element. A great deal of significance is attached to
the order in which they are placed.
The minOccurs in the element
signifies the minimum number of times that the element can occur, whereas,
maxOccurs refers to the maximum number of occurrences. Since both these
attributes have the value of 1, it indicates that the element should be used
only once.
Had the maxOccurs attribute been
assigned a value of 3, and the minOccurs attribute was assigned the value of 1,
the element then could have been used, only upto a maximum of three times.
There is a newly introduced
attribute of 'type' with the element, which was not to be seen with the abc
element. In the case of the type of the element being simple (as is the case
with a predefined type of the XML Schema world, like int or string), you need
to use the type attribute instead.
Thus, the parameters i and j of the function, belong to the type int.
The variables do not need the complexType element. All parameters supplied to
the abc function shall be placed here.
The second element created in
the file is the abcResponse element. This element is visible in the SOAP
response. There is only a single child element called abcResult of type of int,
since the return value is an int.
This wraps up the elucidation of
schema and types elements, as there are only two elements presently available
in the SOAP payload. The information has been gleaned from the function
prototype. Therefore, the code of the functions is of no significance here. Had
you even attempted to add or subtract code from the asmx file, the WSDL file
would still remain unaltered.
The message element, in a very
abstract sense, refers to the content of the messages that are to be sent.
Normally, an entity is assigned a name, if it is to be reused.
<message name="abcSoapIn">
<part name="parameters" element="s0:abc"
/>
</message>
<message name="abcSoapOut">
<part name="parameters"
element="s0:abcResponse" />
</message>
Two messages called abcSoapIn
and abcSoapOut are created in the file. These names have been formed using a
simple algorithm:
• It begins with the function name.
• It is followed by the reserved word
'soap'.
• Then, depending upon whether it is a
request or a response packet, the words 'In' or 'Out' are used, respectively.
The content for the message is
specified using the 'part' child element. The name 'parameters' has been
assigned, since we are dealing with the parameters passed to a function. In any
case, no other name is permitted.
The element attribute defines
the type of the message. Specifying s0:abc as the value, would result in the
SOAP request format being assigned to the element. Thus, the SOAP request will contain the element abc, having two
children, i and j, which are the parameters that the function abc requires.
This is how the elements created earlier in the file, are re-used. The same is
true for the message named absSoapOut, which represents the SOAP response
message.
Now, we move on to the third
element called portType.
<portType name="zzzSoap">
<operation name="abc">
<input message="s0:abcSoapIn" />
<output message="s0:abcSoapOut" />
</operation>
</portType>
A portType consolidates the
operations that are to be performed on the defined messages. Our portType is
assigned the name of zzzSoap, which is formed by conjoining the name of the
class as specified in the asmx file (i.e. zzz), and the word Soap.
The element 'operation' within
the portType tag, has a name attribute initialized to 'abc'. Incidentally,
'abc' also happens to be the name of the function that we want to execute
remotely.
An operation element embodies an
input and an output message. You may
recall that we had recently encountered two messages called abcSoapIn and
abcSoapOut, which are used as the request and response messages, respectively.
The portType element classifies the messages that are created, as either input
or output.
The next element is the binding
element called zzzSoap1.
<binding name="zzzSoap1"
type="s0:zzzSoap">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="abc">
<soap:operation soapAction="http://tempuri.org/abc"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
The original WSDL file is termed
as the binding zzzSoap, but we modified it to zzzSoap1, since there already
exists a portType named zzzSoap.
The type attribute is the name
of a portType, zzzSoap. From what we have encountered so far, a binding
specifies an operation abc, with the 'input' and the 'output' message types.
The binding element that follows, originates from the soap namespace, and is
different from the parent binding, which emanates from the default namespace.
The transport attribute in the
binding element refers to the protocol that will carry the SOAP payload. We
have opted for the http protocol as our transport. However, nothing earth-shaking
would ensue if the protocol of FTP or SMTP were used instead. The 'style'
attribute has been assigned a default value of 'document'. Therefore, the
payload will be considered to be a document and not a Remote Procedure Call
(RPC), where the return values and the parameters are encoded. The binding
spells out only a single protocol, sans any addressing information.
The operation element surfaces
again, with the name attribute having the value of abc. The soapAction
attribute in the operation element from the soap namespace, displays the same
value as seen in the HTTP header SOAPAction. Now, you can identify the
fountainhead of all the values with effortless ease. The style attribute has
already been explained above.
There exist two more child
elements, input and output. Both these child elements possess the same content,
i.e. an element body belonging to the soap namespace. It is the value assigned
to this element, that determines how the message parts are to appear in the
SOAP Body element. It follows the Envelope element in the SOAP payload.
The 'use' attribute can take
either of the two values, 'encoded' or 'literal'. The 'encoded' value refers to
an abstract type, whereas, the 'literal' value uses a schema definition created
in the types element.
Finally, we arrive at the last
element of service, which is assigned the name of zzz.
<service name="zzz">
<port name="zzzSoap2"
binding="s0:zzzSoap1">
<soap:address location="http://localhost/a.asmx"
/>
</port>
</service>
The value assigned to this
service name determines the name of the cs file. More importantly, it decides
the name of the class. If you change the name to zzz1, the C# program shall
also be renamed as zzz1.cs, and it would contain a class named zzz1. This name
is obtained from the WebService directive.
A port element child named as
zzzSoap2, is used to steer clear of any confusion. We do not use this port name
elsewhere. It is the port element that consolidates the bindings zzzSoap1 with
the help of the 'binding' attribute.
The next element of 'address'
from the soap namespace, has the location attribute initialized to the name of
the asmx file, which contains the code of abc. You may recall that the same
value had been used for the Url property in the proxy.
Meanwhile, this concludes an explanation of the WSDL file. Incidentally, we are not over and done with it yet. The specifications are pretty abstract, and we still have miles to go before we sleep!