12
WSDL and DISCO
DISCO
The discovery tool disco accepts
the name of the asmx file. On executing the command, it creates three files in
the folder, viz. a.disco, a.wsdl and results.discomap.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System.Web.Services;
public class zzz
{
[WebMethod()]
public string abc(string i , string j)
{
return i+j;
}
}
>disco http://localhost/a.asmx
Microsoft (R) Web Services Discovery Utility
[Microsoft (R) .NET Framework, Version 1.0.2914.16]
Copyright (C) Microsoft Corp. 1998-2001. All rights reserved.
Disco found documents at the following URLs:
http://localhost/a.asmx?disco
http://localhost/a.asmx?wsdl
The following files hold the content found at the
corresponding URLs:
.\a.disco <-
http://localhost/a.asmx?disco
.\a.wsdl <-
http://localhost/a.asmx?wsdl
The file .\results.discomap holds links to each of these files.
The a.wsdl file is fairly wieldy
and has already been dealt with in one of the preceding chapters. Hence, we
have not displayed it here. Alternatively, a .disco file can also be generated
by specifying the URL of http://localhost/a.asmx?disco in the browser.
a.disco
<?xml version="1.0" encoding="utf-8"?>
<discovery
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="
http://schemas.xmlsoap.org/disco/ ">
<contractRef
ref="http://localhost/a.asmx?wsdl"
docRef="http://localhost/a.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />
<soap
address="http://localhost/a.asmx"
xmlns:q1="http://tempuri.org/" binding="q1:zzzSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/" />
</discovery>
results.discomap
<?xml version="1.0" encoding="utf-8"?>
<DiscoveryClientResultsFile
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Results>
<
DiscoveryClientResult
referenceType="System.Web.Services.Discovery.ContractReference"
url="http://localhost/a.asmx?wsdl" filename="a.wsdl" />
<DiscoveryClientResult
referenceType="System.Web.Services.Discovery.DiscoveryDocumentReference"
url="http://localhost:8080/a.asmx?disco" filename="a.disco"
/>
</Results>
</DiscoveryClientResultsFile>
The disco file is an XML
document, which starts with a root element of discovery. The URI from where all
the elements originate is http://schemas.xmlsoap.org/disco/. The contactRef element,
along with its attributes, is of vital significance here. The ref attribute
refers to the WSDL file, while the docRef attribute refers to the asmx file.
The default namespace mutates to http://schemas.xmlsoap.org/disco/scl/.
The next element is soap, where
the address attribute refers to the a.asmx file on the server, and the binding
refers to zzzSoap. Using this binding, the WebService is located from within
the WSDL file. The results.discomap file is also an XML document. Here, the
root element is DiscoveryClientResultsFile, which is followed by the Results
element. This is followed by two DiscoveryClientResult elements, which refer to
the two files named a.wsdl and a.disco, which have been created by the DISCO
program. The url attribute contains the url that creates these files.
This chapter shall now dissect
the details of the WSDL specification thoroughly, which have not been touched
upon, so far.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System.Web.Services;
public class zzz
{
[WebMethod()]
public string abc(string i , string j)
{
return i+j;
}
}
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" nillable="true" type="s:string" />
<s:element minOccurs="1" maxOccurs="1"
name="j" nillable="true" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="string" nillable="true"
type="s:string" />
</s:schema>
</types>
<message name="abcHttpPostIn">
<part name="i" type="s:string" />
<part name="j" type="s:string" />
</message>
<message name="abcHttpPostOut">
<part name="Body" element="s0:string"
/>
</message>
<portType name="zzzHttpPost">
<operation name="abc">
<input message="s0:abcHttpPostIn" />
<output message="s0:abcHttpPostOut" />
</operation>
</portType>
<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 binding="s0:zzzHttpPost">
<http:address
location="http://localhost:8080/a.asmx" />
</port>
</service>
</definitions>
zzz.cs
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.Web.Services;
public class zzz :
System.Web.Services.Protocols.HttpPostClientProtocol
{
public zzz()
{
Url = "http://localhost:8080/a.asmx";
}
[System.Web.Services.P
rotocols.HttpMethodAttribute(typeof(System.Web.
Services.Protocols.XmlReturnReader),
typeof(System.Web.Services.Protocols.HtmlFormParameterWriter))]
[return:
System.Xml.Serialization.XmlRootAttribute("string",
Namespace="http://tempuri.org/", IsNullable=true)]
public string abc(string i, string j)
{
return ((string)(this.Invoke("abc", (this.Url +
"/abc"), new object[] {i,j})));
}
}
b.cs
public class aaa
{
public static void Main()
{
zzz a = new zzz();
string b = a.abc("hi","bye");
System.Console.WriteLine(b);
}
}
a.bat
WSDL /protocol:HttpPost aa.wsdl
Csc /t:library zzz.cs
Csc b.cs /r:zzz.dll
b
Formatted Trace
SOAP request
i=hi&j=bye
SOAP response
<?xml version="1.0" encoding="utf-8"
?>
<string
xmlns="http://tempuri.org/">hibye</string>
Unformatted Trace
SOAP request
POST /a.asmx/abc HTTP/1.1
i=hi&j=bye
Output
Hibye
The asmx file has a function
named abc, which takes two strings and returns a single string. Then, in the
browser, we specify the URL as http://localhost/a.asmx?WSDL, which results in
the generation of a wsdl file.
In the wsdl file seen above, we
will lay emphasis only that portion which deals with a POST request. A POST
request is different from a GET in one significant way. The parameters to a GET
are passed in the URL, whereas in a POST, they are dispatched in a separate
packet, after the headers have been sent across.
As always, the wsdl file begins
with the definitions root tag. This is
followed by the element abc that is made up of two elements viz. i and j, which
are the parameters to the function abc. The message abcHttpPostIn comprises of
two parts, one each for the variables named i and j. The message abcHttpPostOut
contains a single part called Body. The port type determines the messages that
will be used for input and output.
In the binding, the verb in
focus is POST, and not GET. The input element uses the content element from the
mime namespace, which ensures that the parameters are sent across as URLencoded.
The output element uses the mimeXml element, with Body as its part. The service
element remains unaltered.
The client program is generated
by running the wsdl program as:
WSDL /protocol:HttpPost aa.wsdl
Since we have opted for
HttpPost, it is the class zzz that is now derived from the class
HttpPostClientProtocol, instead of the default protocol option of SOAP.
The HttpMethodAttribute has two
types:
• XmlReturnReader
• HtmlFormParameterWriter.
These types establish the method
by which, the data is received and dispatched. When data is sent over, the
class or type of HtmlFormParameterWriter is used, whereas, it is the type of
XmlReturnReader that is utilized, when the data is received. As usual, there is
no help available on these classes.
The return: specifies that the
return value will be encoded in the form of a simple string. Thus, if you
examine the output, you will realize that it is a simple XML document, where
the return value is enclosed within a string element. The request too is sent
as a separate packet, since the verb is set to POST. Thus, we have divulged
both, the formatted and unformatted outputs to you.
The wsdl program can generate a
client for SOAP, GET and POST. By using the GET and POST verbs, any device
other than a browser, can also be used to communicate with a web server, with
the help of WSDL.
In the operation element, the
location has to be a relative URI, since this value is merged with the location
attribute of the address element. If we change a single line in the output
element to the following:
<mime:content type="text/xml" />
an exception is thrown. This is
due to the fact that the system does not anticipate the inclusion of an element
string in the return packet. The content tag is employed to avoid defining a
new element for every MIME format. This element is used in a situation where
there is nothing more to convey about the format, except the MIME type.
Since only a single part is
present, the part attribute is optional. A MIME type string has two portions,
which are separated by a / symbol, such as- text/xml, image/gif. If no MIME
type has been specified, it is an indication that we are contented and at ease
with all of them. The mimeXml element is used, when the XML payload is not SOAP
compliant. To be SOAP compliant, the root element must be Envelope. The payload
that we receive, does not begin with the envelope tag. Hence, the element is
indispensable.
The request received in the
above POST has a schema, which is specified by the mimeXml element. The part
attribute refers to a part called Body, which is created in the message
element, and comprises of a simple string. The part attribute can be
sidestepped completely, since only one part is present.
wsdl /server aa.wsdl
zzz.cs
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 abstract class zzz : System.Web.Services.WebService
{
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/abc",
Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public abstract string abc(string i, string j);
}
The last option of wsdl is
server. It takes a wsdl file and generates an abstract class. This class is
derived from WebService. As there is no code present in a WSDL file, the
function abc is marked as abstract, in the zzz class.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System.Web.Services;
public class zzz
{
[WebMethod()]
public void abc()
{
}
}
After having removed the lines
that are not required, aa.wsdl file looks like shown below.
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/">
<message name="m" />
<portType name="pt">
<operation name="abc">
<input message="s0:m" />
<output message="s0:m" />
</operation>
</portType>
<binding name="b1" type="s0:pt">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="abc">
<soap:operation soapAction="http://tempuri.org/abc"
/>
<input>
<soap:body />
</input>
<output>
<soap:body/>
</output>
</operation>
</binding>
<service name="zzz">
<port binding="s0:b1">
<soap:address
location="http://localhost:8080/a.asmx" />
</port>
</service>
</definitions>
b.cs
public class aaa
{
public static void Main()
{
zzz a = new zzz();
a.abc();
}
}
a.bat
del *.dll
del *.exe
wsdl aa.wsdl
csc /t:library zzz.cs
csc b.cs /r:zzz.dll
b
SOAP request
<soap:Body />
SOAP response
<soap:Body>
<abcResponse xmlns="http://tempuri.org/" />
</soap:Body>
Here, we encounter the smallest
possible WSDL file, which neither sends nor receives any data from the server.
Let us now tread over familiar territory, which we have covered in the past. We
would also be scrutinizing the WSDL specifications exhaustively.
At the bottom of the aa.wsdl
file, exists a service element named zzz. The address element from the soap
namespace is optional. However, if it is omitted, the Url property does not get
initialized. As a result, the client is unable to connect to any Web Service.
If we remove the port element, the class in the .cs file assumes the name of
b1, which is the name of the binding.
Also, the Url property does not
get initialized. The binding contains all the essential information for WSDL.
The service is merely one step ahead of the binding.
aa.wsdl
<service name="aaa">
<port binding="s0:b1">
<soap:address
location="http://localhost:8080/a.asmx" />
</port>
</service>
</definitions>
zzz.cs
public class b1 :
System.Web.Services.Protocols.SoapHttpClientProtocol {
public class b11 :
System.Web.Services.Protocols.SoapHttpClientProtocol {
We now add one more service
called aaa, to the end of the wsdl file. Multiple service elements are
permissible in the WSDL file. This results in two classes in the client proxy,
viz. b1 and b11. If we add one more service called bbb, the class b12 will get
freshly added.
Each service element becomes a
class in the proxy. However, the name of the service no more decides on the
name of the class but the name of the binding.
aa.wsdl
<service name="zzz">
<port name="p1" binding="s0:b1">
<soap:address
location="http://localhost:8080/a.asmx" />
</port>
<port name="p2" binding="s0:b1">
<soap:address
location="http://localhost:8080/a.asmx" />
</port>
</service>
So far, we have been screaming
hoarse from rooftops, that the service name determines the name of the class in
the client proxy. However, in the case of multiple services, it is the name of
the binding that determines the class name, irrespective of the fact that two
ports exist within the same service, with both using the same binding. Legally,
it is permissible to have different port names, such as p1 and p2. However, the
two classes that get created in the zzz.cs file, would be b1 and b11. Thus, the
real meat of the matter lies in the ports, and not in the service element.
Let us now attend to some
general issues relating to WSDL. First of all, WSDL offers a binding for SOAP
1.1 endpoints. This is because, a major part of the WSDL specifications
converges around SOAP. In a sense, the specifications of both, SOAP and WSDL, were
developed simultaneously.
You would notice that a large
number of elements in WSDL originate from the soap namespace. Therefore, there
is a need to specify the address for a SOAP endpoint, as well as, the URI for
the SOAPAction HTTP header.
The WSDL is required to betoken
the fact that the binding that shall be used, would be the SOAP 1.1 protocol.
The binding grammar is not exhaustive, since the SOAP specifications keep
evolving on a continuous basis, thereby, resulting in amendments and enhancements
to the WSDL specifications.
Let us now veer our focus on to
the binding attribute from the soap namespace. It is mandatory for the element
soap:binding to be present in the binding element, when a SOAP payload is sent
across the wire. The duty of this element is to enforce the rules of the SOAP
protocol, when the binding is created. In other words, the payload should
contain the following : an Envelope, an optional Header and a Body.
The binding element is
indifferent to the encoding or format types being used. It only accepts two
attributes:
• Transport, which is a URI.
• Style, which is either document or
rpc. The default is document.
The transport attribute
establishes the transport protocol that would be used to carry the SOAP packet
across. To this point, the http protocol was being used to serve this purpose.
However, we can use the other transports, such as- the Simple Mail Transfer
Protocol SMTP, or the File Transfer Protocol FTP. In the beta copy, if we
replace http with ftp, WSDL reports an error. The client proxy projects the
class as being derived from SoapHttpClientProtocol; thus, giving the impression
that all is hunky-dory.
The operation element is akin to
the binding element, wherein the same element name appears in both, in the wsdl
space, as well as, in the soap space. This element refers to the soap operation
as a complete entity. It has to be a child element within the operation
element, and it accepts two attributes, viz. soapAction and style.
The soapAction attribute is the
most important attribute, since the SOAPAction HTTP header derives its value
from it. The value that is entered in this URI must be an absolute URI. This
value is used as the first parameter to the attribute
SoapDocumentMethodAttribute.
WSDL generates no errors at all,
even in the eventuality of no value being supplied; instead, the value of the
parameter to the attribute is set to 'null'. However, when we finally run the
program, an exception is thrown, since the server fails to recognize the value
of the header named SoapAction. Thus, a valid URI must be specified.
For SOAP protocol bindings other
than HTTP, such as SMTP, a value cannot be specified. Hence, the operation
element is optional.
Let us now progress onto the
body element. This element is used twice, i.e. once each in the input and
output elements. The body element specifies the appearance of the message parts
inside the SOAP Body element. In all, four attributes can be used with it:
• Parts
• Use
• EncodingStyle
• Namespace
These attributes, along with the
style attribute, will be analysed a little later in the chapter.
The last soap element is the
address element. This element is employed to assign an address or a URI to a
port. We cannot assign more than one address to the port that we wish to bind
to. Moreover, the value or the address specified here, must correspond to the
transport protocol that is in use. For example, if we are using the SMTP
transport, the location should be an e-mail address.
After having dealt with the soap
namespace elements, let us revert back to the smallest WSDL file again. A
service merely groups the ports together. The name attribute is optional. If it
is present, it determines the name of the class and the file. If it is absent,
the name of the class becomes Item, while the name of the file becomes
output.cs.
We cannot have more than one service,
each without a name. Also, as reiterated earlier, multiple services can have
multiple bindings, and each service can have multiple ports, subject to the
port names being unique. The names of the bindings determine the names of the
classes. The first service name is used for the name of the file. Multiple
ports are permitted in a service, but these ports do not communicate with each
other. Thus, we cannot state that the output of a port should become the input
to another port.
If a service has ports that do
not share a port type, and at the same time, they use different bindings or
addresses, these ports are to be used as alternatives.
Once again, compared to the
binding, the service and the port appear insignificant. This is because, the
port defines an endpoint by stating a single address for the binding. The port
element contains the attributes of name and binding. If there is only one port,
then the name is optional, but the binding attribute is obligatory. As per the WSDL specifications, a port
cannot specify more than one address. However, if we do hold two address
elements, only the first element that is encountered is put to use, and a
warning is displayed. The only binding information that must be associated with
a port is, an address or a URL. All the rest results in an error.
In our opinion, the binding
element is one of the most crucial elements. The binding derives from a port
type, and it specifies a protocol for transport. We can have more than one
binding, derived from the same port type. Then, an operation is defined with
the SoapAction header. This is followed by the actual input and output section.
A binding coalesces the message
formats and the protocol for operations. All the above elements are inevitable
and inescapable for a binding.
The binding element has a name,
which is used by a service. It also has a type, which specifies a port type. If
the name is omitted, the same set of rules that we explicated earlier, would be
applicable. The type attribute is mandatory, since it introduces the port type
details. The binding may also contain a fault element, which deals with faults,
as the name itself suggests.
The element 'operation' that we
place within a binding, specifies the binding information for an operation. The
name assigned here must be the same, as the one specified for the operation
that is created in the port type. It is incorrect to use different names for
the operation in the binding and the port type. If more than one protocol is
specified, a warning is issued.
Further, a binding is not
authorised to specify any address information, since this is the sole
prerogative of the port element.
A port type is arguably the key
to unlocking the mysteries of WSDL. A binding derives from the port type. To
define a port type in formal terms, it is a compendium of abstract collections
and messages. The port type is normally assigned a name, since it can then be
used in the binding element. The lone element that is worthy of being placed
within the portType is, the operation element.
The operation element name must
match with the name in the bindings element. Resorting to different names in
each of the operation elements may result in whopping errors, as an outcome of
which, the zzz.cs file may refuse to be written at all!
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System.Web.Services;
public class zzz
{
[WebMethod()]
public void abc()
{
}
[WebMethod()]
public void pqr()
{
}
}
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:element>
<s:element name="abcResponse">
<s:complexType />
</s:element>
<s:element name="pqr">
<s:complexType />
</s:element>
<s:element name="pqrResponse">
<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>
<message name="pqrSoapIn">
<part name="parameters" element="s0:pqr"
/>
</message>
<message name="pqrSoapOut">
<part name="parameters"
element="s0:pqrResponse" />
</message>
<message name="abcHttpGetIn" />
<message name="abcHttpGetOut" />
<message name="pqrHttpGetIn" />
<message name="pqrHttpGetOut" />
<message name="abcHttpPostIn" />
<message name="abcHttpPostOut" />
<message name="pqrHttpPostIn" />
<message name="pqrHttpPostOut" />
<portType name="zzzSoap">
<operation name="abc">
<input message="s0:abcSoapIn" />
<output message="s0:abcSoapOut" />
</operation>
<operation name="pqr">
<input message="s0:pqrSoapIn" />
<output message="s0:pqrSoapOut" />
</operation>
</portType>
<portType name="zzzHttpGet">
<operation name="abc">
<input message="s0:abcHttpGetIn" />
<output message="s0:abcHttpGetOut" />
</operation>
<operation name="pqr">
<input message="s0:pqrHttpGetIn" />
<output message="s0:pqrHttpGetOut" />
</operation>
</portType>
<portType name="zzzHttpPost">
<operation name="abc">
<input message="s0:abcHttpPostIn" />
<output message="s0:abcHttpPostOut" />
</operation>
<operation name="pqr">
<input message="s0:pqrHttpPostIn" />
<output message="s0:pqrHttpPostOut" />
</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>
<operation name="pqr">
<soap:operation soapAction="http://tempuri.org/pqr"
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 />
</operation>
<operation name="pqr">
<http:operation location="/pqr" />
<input>
<http:urlEncoded />
</input>
<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 />
</operation>
<operation name="pqr">
<http:operation location="/pqr" />
<input>
<mime:content
type="application/x-www-form-urlencoded" />
</input>
<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>
We now display two functions
through our web service, in the asmx file. Let us cast the spotlight on the
wsdl file, which is displayed exclusive of any modifications, to facilitate
ameliorated understanding of it.
There are three different verbs
that a wsdl file supports, viz. GET, POST and SOAP. We shall be expounding each
one of the three verbs now.
First, we commence with the SOAP
part of the WSDL file. The WSDL file has a 'types' section, which is
independent of the method of access. These types may be employed by any of the
verbs, and hence, are common to all. The types element is merely an XML schema,
where different types are created, and which can be referred to by the
elements. Since there are two functions in the asmx file, namely, abc and pqr,
an element is also defined for every function that has been created. The
element represents the parameters passed to the function. In our case, since
the functions take no parameters, the elements are empty.
Functions return values.
Therefore, an element that contains the name of function, followed by the word
'Response' is distinctly perceptible. This covers the explanation of the
elements abcResponse and pqrResponse.
The service name is insouciant
towards the number of functions. Hence, it refuses to change in any way. The
binding now has two operations, named abc and pqr, with each representing the
individual functions. Thus, a wsdl file can have a variety of operations, but
the portType remains the same. Here, two operations called abc and pqr, are
posited.
Like before, every operation
consists of an input and output section. However, the difference here rests in
the fact that, these input and output elements represent the parameters that
are being sent and received, respectively. The input and output elements
utilize the messages that are created in the file. This is for the reason that,
the parameters and return values of each function vary.
In the case of a message, it is
formed by utilising the individual elements, which are created in the file.
This explicates the concept that forms the basis of the implementation of
multiple functions in SOAP.
In the service element, there
exist three individual port names that use a different binding, but share the
same address element. The SOAP port uses the address element from the soap
namespace, while GET and POST use it from the http namespace. This is where the
concept of a service comes to prominence.
The same class zzz is generated,
but it is derived from a different class. Hence, it uses a different binding.
The binding for the verb POST, which is akin to SOAP, consists of two
operations for the two functions, named abc and pqr. The rules of URL encoding
are specified in the input, and since there is no output, the output element is
bereft of all content.
The GET verb is similar to the
POST verb. The only variation lies in the input, where it utilises the
urlEncoded element, since the parameters in a GET are passed as part of the
URL. However, they are encoded in much the same way, as is done in the POST.
The output element is empty,
just like a POST. The port type structure is the same for GET and POST; but
unlike SOAP, this element does not provide any useful information. This happens
because, the messages that form its basis, are all empty. Thus, the message
concept is more germane to the SOAP protocol, rather than to the GET or POST
verbs.
Reverting back to the port type,
a name attribute has to be specified here, since many ports will be created in
the WSDL file. Each of these has to be uniquely identified.
For the next program, remove the
pqr function and give a return value of 100 for the abc function.
a.asmx
public int abc() {
return 100;
}
The wsdl file has been created
manually and represents a One-way operation. If you examine the file minutely,
you would be able to discern the fact that there is no output element visible
in either the port type, or in the binding.
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/">
<message name="m" />
<portType name="pt">
<operation name="abc">
<input message="s0:m" />
</operation>
</portType>
<binding name="b1" type="s0:pt">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="abc">
<soap:operation soapAction="http://tempuri.org/abc"
/>
<input>
<soap:body />
</input>
</operation>
</binding>
<service name="zzz">
<port binding="s0:b1">
<soap:address
location="http://localhost:8080/a.asmx" />
</port>
</service>
</definitions>
SOAP response
<abcResult>100</abcResult>
This is perfectly legal, as it
signifies that a SOAP request is being sent over, although there would be no
response at all. The server being privy to this manipulation, merrily sends
back an answer. But, since it is a One-Way operation, the Invoke function
disregards it completely.
The second operation is called a
request-response operation. This is the most commonly used one, and it serves
as a very vital foundation to a significant number of our programs in this
book. This operation takes an input and an output element, along with the
'fault' element that is optional.
The fault element is used to
specify a message format, over and above the protocol specifications. The
request-response paradigm is implemented by the binding. The payload may be
dispatched, either in a single communication, or in two independent ones.
There are two more transmission
primitives that an endpoint can support:
• Solicit response, where the endpoint
sends a message and then receives a message. This is different from a request
response, where the endpoint receives a message and then sends a message.
• Notification, where the endpoint
only sends a message. This is the reverse of the One-Way, where the end point
just receives a message.
These primitives are called
operations. The WSDL specification only defines One-Way and request-response
primitives. Thus, we cannot demonstrate examples of the other two.
Now let us delve upon the
concept of 'types', before moving on to the last major element named
'messages'. By using the 'types element', we can create our own custom made
types and elements. Also, when parameters are passed to a function with return
values, two elements get created.
The XSD or XML Schema type
system is referred to, when 'types' are defined. They are eventually used in
messages, irrespective of whether the payload is XML or not. Everything in the
WSDL world can be extended, as a result of which, other type systems can be
added.
As you would have realised, a
WSDL file is capable of taking gargantuan dimensions. Hence, the specifications
recommend that we break this file up into smaller documents. Thereafter, these
smaller files can be coalesced into one large file, by using the import
statement. The documentation element is used to add comments to the code in the
WSDL file.
The first entity that we build
in WSDL is a 'message' element. A message can consist of zero or more parts. A
part is created from the 'type', which in itself is created in the 'types'
section. The 'type', in turn, represents the parameters and return values. We
may use either the 'element' or the 'type' attribute, to refer to elements or
types created in the type section. Every message is assigned a name, since it
would be referred to, in the port Type element.
The part element that describes
the logical and abstract content of a message, can make an appearance more than
once in a message. If we so desire, we may create a complexType in place of an
element, and may even use the type in lieu of the element attribute.
A Message is an abstract
definition of a message content. Finally, the message binding converts the
abstract entity into something concrete.
Now, we shall acquaint you with
various methods available for controlling the format of the SOAP messages, sent
by a SOAP client to a server, and vise-versa.
The SOAP specification yearns
simply for the SOAP message to be a valid XML document. However, it does not
specify the encoding style that should be used. Thus, ASP.Net concedes to the
use of different encoding styles, by providing a set of attributes. These
attributes are then used to control the SOAP payload, by facilitating
customization of every byte that is sent across.
Next, we zero in on customizing
the SOAP packet sent by a Client. Subsequently, we shall be attending to the
server end too.
Sections 5 and 7 of the SOAP
specification, make a mention of two distinct encoding definitions. These give
a detailed description of the manner in which the Body element should be
formatted, and how the parameters within a method should be encoded. However,
these encoding elements are not mandatory. The Asp.Net services support the
requests and responses that ensue these two encodings.
Before we venture into creating
our own web service, the one thing that needs circumspection is, the manner in
which the XML within a SOAP request must be encoded, or formulated. The basic
issue here is to decide whether the XML document should adhere to the XSD
schema or to the rules of the SOAP specification. The advantage of using the
encoding rules of the SOAP world is that they permit variations.
However, the server that handles
the request, must also be equipped to handle all these variations. By employing
an XSD schema, which is the default, we can be very explicit about what is
being sent across.
The parameters and the return
value form the bulk of a SOAP payload. The SOAP specifications subsist, mainly
to define how the parameters and return values shall be sent across.
In the WSDL world, there are two
encoding styles for parameters, viz. Encoded and Literal. Although we are aware
of the fact that this has been discussed earlier, we are now toiling towards
consolidating everything at one place. The style of Encoded encodes the
parameters, using the SOAP specs, as stated in Section 5. On the other hand,
Literal encodes the parameters using a predefined XSD schema. The Web Service
must expect the parameters in the same format, as is sent by the client. Even
if there is a very minor mismatch, the parameters shall not reach the final
destination.
The enum of SoapBindingUse is
used to specify an encoding, using the attribute
SoapDocumentMethodAttribute. Also, the
parameters that dwell within the Body element, are encoded as self-containing
XML documents, since they refer to an XSD schema. The Encoded parameter is
specified by employing the same method, as has been outlined above. The
encoding rules delineated in Section 5 are used here. We are permitted to modify the overall formatting of the SOAP
Body.
The WSDL standard describes two
styles for operation. An operation is a Web Service method, which can be
formatted within the Body element. This does not refer to the optional Header
element. The two styles are RPC and Document, where Document is the default
style. The Document style uses the XSD schema for encoding, whereas, the RPC
style makes use of the SOAP specification.
In the RPC style, all the
parameters are placed within a single element, after the name of the remoted
function has been called. Each child element that is placed below the method
name, is a parameter to the function with the same name. Alternatively, the
Document style specifies or defines XSD schemas, using the WSDL file. The
clients and servers expect the packets to cohere to these schemas. The actual
code that represents these coding styles, has already been revealed earlier.
The SoapRpcMethodAttribute is used for the Rpc encoding.
The parameters to a function can
reside within the Body element in two ways. They can either reside within their
own element, or they can be lodged within one element. The RPC style wraps the
parameters within one element, whereas, the Document encoding is much more
flexible. All the parameters can be wrapped within one element, and a default
namespace can be created for these parameters.
The benefit of this is, the size
of the SOAP payload contracts, since the XML files are always bulkier than the
native data.
To accomplish this, the
Parameter style is set to Wrapped, and the encoding is set to Literal. By
changing the ParameterStyle to Bare, we can ensure that the parameters are
directly beneath the Body element.
A namespace cannot be specified
in an element that wraps parameters. Thus, each parameter must be specified
individually, for all the parameters and return values.
To realize this, an
XmlElementAttribute is added, and then, the Namespace property is set. The word
'return' that ends with a colon (as seen earlier), is of considerable
significance here. The return value is the name of the web service, followed by
the word 'Result'. The WebService method on the server must define an encoding
style that corresponds to the client, by using the same attributes.
The System.Xml.Serialization
namespace contains the attributes, which can be used to change the SOAP
payload, which gets sent across. The XmlElementAttribute is used to amend the
name of the parameter that goes across. However, if the RPC method is implemented,
the SoapElement attribute has to be used.
In the WSDL specifications, the style attribute indicates whether the operation or function is RPC or document. In a RPC style, the messages contain parameters and return values; whereas, in the document style, the message contains documents. The soap:binding element determines the style, where the default is document, and the 'use' attribute specifies either 'encoded' or 'literal'. This value is then employed by WSDL, to determine the attributes that are to be used while generating the proxy.