-8-
The .Net framework recognizes and
acknowledges files with an extension of asmx as a Web Service. Therefore, in
order to cater to the prerequisites of .Net framework, we design a file called
a.asmx, with a class named zzz.
a.asmx
public class zzz
{
public int abc(int i)
{
return i*2;
}
}
Output
Parser Error Message: The page must have a <%@
webservice class="MyNamespace.MyClass" ... %> directive
The class zzz has a function
called abc, that accepts an int as a parameter and returns a value, after
multiplying the parameter by 2. No class can be more uncomplicated and
clear-cut than the one we have written. Yet, we get an error when the file is
loaded as http://localhost/a.asmx in
the browser. This is because, a Web service is a special file, and the
framework is required to handle this exceptional file, a little differently.
So, we need to supplement this file by making some more additions, as shown
below.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
public class zzz
{
public int abc(int i)
{
return i*2;
}
}
In the previous program, since
the directive named WebService was missing, an error was reported. The
directive WebService is followed by the name of the language which has been
initialized to C#, because we will be writing the Web Service, using the C# programming
language. An asmx file may contain a numerous classes, but only one of them
represents the Web Service. Thus, the class property is made equal to zzz. We
spot the following output in the browser:
Output
zzz WebService
zzz
The following operations are supported. For a formal
definition, please review the Service Description.
----------------------------------------------------------------------------
This web service is using http://tempuri.org/ as its default
namespace.
Recommendation: Change the default namespace before the web
service is made public.
Each web service needs a unique namespace to identify it so
that client applications can distinguish it from other ..............
......................
For more details on XML namespaces, see the W3C recommendation
on Namespaces in XML.
For more details on WSDL, see the WSDL Specification.
For more details on URIs, see RFC 2396.
The class zzz is now acknowledged
as a Web Service. For the moment, there are no web methods exposed by our
class. A Web Service permits others to
execute code in our class. We want the function abc to be called with a number,
so that it can majestically return the numbers twice over, than it had been
served with.
No web methods are shown, since
at this point in time, the function abc is inaccessible.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System.Web.Services;
public class zzz
{
[WebMethod]
public int abc(int i)
{
return i*2; } }
Output
zzz
The following operations are supported. For a formal
definition, please review the Service Description.
abc
Click on abc and the screen
changes to accept values in a text box
Click here for
a complete list of operations.
abc
Test
To test, click the 'Invoke' button.
Parameter Value
i:
SOAP
The following is a sample SOAP
request and response. The placeholders shown need to be replaced with actual
values.
POST /a.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/abc"
<?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>
<abc
xmlns="http://tempuri.org/">
<i>int</i>
</abc>
</soap:Body>
</soap:Envelope>
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?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>
<abcResponse
xmlns="http://tempuri.org/">
<abcResult>int</abcResult>
</abcResponse>
</soap:Body>
</soap:Envelope>
HTTP GET
The following is a sample HTTP
GET request and response. The placeholders shown need to be replaced with
actual values.
GET /a.asmx/abc?i=string HTTP/1.1
Host: localhost
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0"
encoding="utf-8"?>
<int
xmlns="http://tempuri.org/">int</int>
HTTP POST
The following is a sample HTTP
POST request and response. The placeholders shown need to be replaced with actual
values.
POST /a.asmx/abc HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: length
i=string
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0"
encoding="utf-8"?>
<int
xmlns="http://tempuri.org/">int</int>
To convert a function into a web
method, we have to add an attribute
named WebMethod from the namespace System.Web.Services. When the asmx
file is now loaded, the screen is flashed with the name of the function, its
parameter names and their data types. In addition, we get an input box to enter
a number. This number becomes the value of the parameter i. When we keyed in
the number 12 and clicked on the Invoke button, to our utter amazement, we saw
the number 24 displayed, as shown below.
Output
<?xml version="1.0" encoding="utf-8"
?>
<int
xmlns="http://tempuri.org/">24</int>
This happens to be an xml file.
Since the return value of our function is an int, the number 24 is enclosed
within the int tag. The html file that we had taken notice of, and had attended
to, was honestly, all smokes and mirrors.
Whenever the framework stumbles
upon a file with an asmx extension, it treats it very differently from an aspx
file. It finds out all the functions in the Web Service class that are tagged
with an attribute of WebMethod. It then creates an HTML file. Clicking on the
invoke button results in the execution of a URL by passing it parameters.
Next, we are interested in
calling the function abc, with a parameter i, which has a value of 23. However,
when we actually call the function abc, which has to be summoned from the Web
Service zzz in the file a.asmx, the following URL has to be entered in the IE
address bar: http://localhost/a.asmx/abc?i=23
The output window displays the
following:
Output
<?xml version="1.0" ?>
<int
xmlns="http://tempuri.org/">46</int>
Thus, if we are aware about the
existence of a Web Service and are responsive towards its nuts and bolts, we
can easily call the code from it, using a URL. The parameters to the functions
are passed as HTML parameters. Assuming that we had two parameters named i and
j in the function abc, we would enter the URL as follows: http://localhost/a.asmx/abc?i=12&j=10.
On placing an error in the above
C# program, we noticed that our Web Service is actually a dll. No extra code is
added to the Web Service file, unlike in a control. Also, a Web Service does
not derive from any other class. A Web Service internally uses SOAP, or the
Simple Object Access Protocol, to bring this magic into being!
One more thing that you should be
well conversant with, is the Service Description (WSDL file). If you click on
the Service Description link, you will see an XML file that has obviously not
been written by us. Let us now try to appreciate, what goes into this file.
WSDL file
<?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: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" />
</message>
- <message name="abcHttpGetOut">
<part
name="Body" element="s0:int" />
</message>
- <message name="abcHttpPostIn">
<part
name="i" 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>
This XML file gives us all the
details about the Web Service. It represents the Web Service, but without the
code.
Let us explain the how's and
why's of it.
A WSDL document defines services
as collections of network endpoints, or ports. The tag called definition
describes the Web Service, but in a non-programming manner. All Web Services
are based on SOAP.
A Service Definition Language is
made up of six major elements:
types, which
provides data type definitions used to describe the messages exchanged.
message, which
represents an abstract definition of the data being transmitted. A message
consists of logical parts, each of which is associated with a definition within
some type system.
portType, which is a
set of abstract operations. Each operation refers to an input message and
output messages.
binding, which
specifies concrete protocol and data format specifications for the operations
and messages defined by a particular portType.
port, which
specifies an address for a binding, thus defining a single communication
endpoint.
service, which is
used to aggregate a set of related ports.
The WSDL file that has been
generated, helps us to figure out the number of functions in the Web Service.
The parameters, their data types and the return value are also specified along
with the function names. This description is sufficient to execute a function.
Observe that there is no sign of any code in the asmx file. Thus, the WSDL file
is not concerned about whether the code is in Java or C# or in any other
language. Since the file is machine generated, we will not spend more time
deciphering it.
Let us now summon the Web Service
from our program, which is written in C#.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System.Web.Services;
public class zzz
{
[WebMethod]
public int abc(int i)
{
return i*2;
}
}
Firstly, we write the following
URL and click on the Service Description link, and then copy whatever file is
displayed in the file named, a.wsdl in the c:\inetpub\wwwroot\bin sub-directory.
We now want some program to
generate a C# program, which can act like our Web Service. The program that we
shall be running, using the command laid down below, is called WebServiceUtil.
Very soon, we shall be explaining as to what the various options in this
command signify.
>wsdl.exe /l:CS /n:nnn a.wsdl
This will create a file called
zzz.cs, since our Web Service class was called zzz. /n:nnn adds namespace nnn
to the class. In case you receive any errors, you should ensure that the first
line, <?xml version="1.0" ?>, begins at the first column, and
the file thereafter starts with a tag on every line. Also if you have selected
and copied the file from your browser, you will have to remove the - sign
preceeding every line.
The contents of zzz.cs are as
follows:
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.
namespace nnn {
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) {
object[]
results = this.Invoke("abc", new object[] {
i});
return
((int)(results[0]));
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public
System.IAsyncResult Beginabc(int i, System.AsyncCallback callback, object
asyncState) {
return
this.BeginInvoke("abc", new object[] {
i}, callback, asyncState);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public int Endabc(System.IAsyncResult
asyncResult) {
object[]
results = this.EndInvoke(asyncResult);
return
((int)(results[0]));
}
}
}
This program has been generated
by the wsdl program. The name of the class is given as zzz, which is derived
from
System.Web.Services.Protocols.SoapHttpClientProtocol. The function abc
accepts one parameter i.e. int i. Before we go on to explain how this code gets
generated, let us first convert this machine generated code into a library
zzz.dll, with the help of the following csc command:
>csc /t:library /r:system.web.services.dll zzz.cs
Next, we have to call code from
our Web Service. For this, we create a file a.aspx in the inetpub/wwwroot
sub-directory.
a.aspx
<%@ Import Namespace="nnn" %>
<%@ language=C# %>
<form action="a.aspx" method="post"
runat="server">
<script language="C#" runat=server>
void abc(Object a1, EventArgs e)
{
zzz a = new zzz();
int i = a.abc(Int32.Parse(aaa.Text));
Response.Write(i.ToString());
}
</script>
<asp:textbox id="aaa" runat="server"/>
<asp:button type=submit text="Click"
OnClick="abc" runat="server"/>
</form>
The framework looks into the bin
sub-directory for the code of the objects. On sighting it, the code gets
executed.
The above program will generate a
compilation error, if zzz.dll is not present in the bin sub-directory or if
there are more dlls in the directory. This is because, the code for the class
zzz resides in the zzz.dll, moreover, the compiler is not informed about the
location and the name of the dll name. This can be done using the /R: option.
To solve the mystery of locating
the dll, we take the assistance of the web.config file.
web.config
<configuration>
<system.web>
<compilation debug="false">
<assemblies>
<add assembly="zzz"/>
</assemblies>
</compilation>
</system.web>
</configuration>
To change the default behavior of
anything in the ASP.Net world, we have to
turn to the configuration file. The 'add assembly' option adds the dll that has
been assigned to it, to the csc compiler. To be precise, it appends the dll
with the /r: option to the compiler, while compiling any cs file. This assembly
can be present anywhere on our hard disk. The /bin sub-directory is a special
directory, which is checked only for our business objects. This is how the
framework can be customized to work with our files.
Now, if you load the aspx file
using http://localhost/a.aspx, you will notice a button and a textbox. If you
type in the number 12 and click on the button, the abc function in the aspx
file will be called. In the function abc, a new zzz object called a, is
created, and the function abc is called off it. This function is supplied with
a parameter, which is the text entered in the TextBox, after converting it into
an int. The return value of this function is displayed through the Write
function. Any number that we enter is multiplied by 2, and then the value is
returned.
Note that the code for the
multiplication is not present in the zzz class. To further prove this point, we
merely open the asmx file and multiply by 3, instead of 2. Now, if we click on
the button, we will observe the numbers being multiplied by 3. Are you feeling
perplexed already? If so, it would be sensible for you to revise the above
text, before proceeding any further.
We are doing the following to
prove to you that, you can easily change the way ASP+ looks at the world.
The VB sample in the
documentation derives from the WebService class, while, the C# sample does not.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System;
using System.Web.Services;
public enum yyy
{
b1 = 10,
b2 = 20
}
public class xxx
{
public int i1;
public double d1;
}
public class zzz
{
[WebMethod]
public String a1()
{
return "vijay";
}
[WebMethod]
public int[] a2()
{
int[] a = new int[2];
a[0] = 10;
a[1] = 20;
return a;
}
[WebMethod]
public yyy a3()
{
return yyy.b1;
}
[WebMethod]
public xxx a4()
{
xxx x = new xxx();
x.i1=10;
x.d1 = 10.1;
return x;
}
[WebMethod]
public xxx[] a5()
{
xxx [] x = new xxx[2];
x[0] = new xxx();
x[0].i1=3;
x[0].d1=3.1;
x[1] = new xxx();
x[1].i1=9;
x[1].d1 = 9.1;
return x;
}
}
We have created 5 functions named
a1 to a5 in our Web Service. The display order may not be in the order of
creation. The point we are making here is that, we are allowed to return any
data types that we like. Let us start by clicking on each function and understanding
the output. The first function, a1, simply returns a string.
Output
<?xml version="1.0" encoding="utf-8"
?>
<string
xmlns="http://tempuri.org/">vijay</string>
The value 'vijay' is placed
within a tag called string, since our function returns a string. The next
function, a2, returns an array of ints.
Output
<?xml version="1.0" encoding="utf-8"
?>
<ArrayOfInt
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://tempuri.org/">
<int>10</int>
<int>20</int>
</ArrayOfInt>
The individual ints are tagged
with the int tag, and the entire array is enclosed in an ArrayOfInt tag. Thus,
we can also return an array of any data type.
The next click will call function
a3, which returns the value of an enum. An enum is a class that contains names
that represent values.
Output
<?xml
version="1.0" encoding="utf-8" ?>
<yyy
xmlns="http://tempuri.org/">b1</yyy>
The enum member that is returned,
is placed in a tag, that is the name of the enum class yyy.
Function a4 returns an object of
a class xxx. This class has two members, i1 and d1. Hence, the output is
displayed as follows:
Output
<?xml version="1.0" encoding="utf-8"
?>
<xxx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://tempuri.org/">
<i1>10</i1>
<d1>10.1</d1>
</xxx>
The last function, a5 is like the
one above, but it returns an array of xxx objects.
Output
<?xml version="1.0" encoding="utf-8"
?>
<ArrayOfXxx
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://tempuri.org/">
<xxx>
<i1>3</i1>
<d1>3.1</d1>
</xxx>
<xxx>
<i1>9</i1>
<d1>9.1</d1>
</xxx>
</ArrayOfXxx>
The tag, ArrayOfXxx encloses the
entire output. Each member of the array is placed within the tag xxx, and the
individual members are placed within their own tags. By making use of a Web Service, we are at a liberty to pass
any data types, as return values or as parameters. Thus, there are no
restrictions. We will leave it as an exercise for you to run the same Web
Service from an aspx file.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Services;
public class zzz
{
[WebMethod]
public DataSet abc()
{
SqlConnection c = new
SqlConnection("server=localhost;uid=sa;pwd=;database=NorthWind");
SqlDataAdapter co = new SqlDataAdapter("select productid,productname
from Products where productid='1'",c);
SqlDataAdapter co1 = new SqlDataAdapter("select
customerid,companyname from Customers where customerid='BOLID'", c);
DataSet ds = new DataSet();
co.Fill(ds, "zzz");
co1.Fill(ds, "yyy");
return ds;
}
}
Output
<?xml
version="1.0" encoding="utf-8" ?>
<DataSet
xmlns="http://tempuri.org/">
<xsd:schema id="NewDataSet"
targetNamespace="" xmlns=""
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="NewDataSet"
msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="zzz">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="productid"
type="xsd:int" minOccurs="0" />
<xsd:element
name="productname" type="xsd:string"
minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="yyy">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="customerid"
type="xsd:string" minOccurs="0" />
<xsd:element
name="companyname" type="xsd:string"
minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<diffgr:diffgram
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<NewDataSet xmlns="">
<zzz diffgr:id="zzz1"
msdata:rowOrder="0">
<productid>1</productid>
<productname>Chai</productname>
</zzz>
<yyy diffgr:id="yyy1"
msdata:rowOrder="0">
<customerid>BOLID</customerid>
<companyname>Bσlido Comidas preparadas</companyname>
</yyy>
</NewDataSet>
</diffgr:diffgram>
</DataSet>
One thing that is very evident is
that, Microsoft is in love with XML and finds it irresistable. Hence, we see
XML popping out of everywhere.
In the above Web Service, we are
connecting to the database NorthWind and creating two SQL statements that will
return one record each, from two separate tables. These select statements are
added to our dataset object and the object is then returned. The output is in
the form of an appealingly formatted XML file.
Let us try to understand this
file now.
As usual, the XML file starts
with the xml version number. It is then followed by a tag called DataSet.
DataSet informs us that the data given within it is from a database. The first
dataset with the name zzz, becomes the name of our element. This is succeeded
by the field names or the schema.
The same procedure is repeated
for the second table in the data set. Then, we have a tag called NewDataSet, followed
by the name of the first dataset zzz, in a tag form. Then, we have the values
from the database enclosed by the field names, once again in tags. The same
process is reiterated for the other table too.
a.asmx
<%@ WebService Language="C#" Class="zzz"
%>
using System;
using System.Web.Services;
public class zzz : WebService
{
[WebMethod(EnableSession=true)]
public String abc()
{
if (Session["aa"] == null)
{
Session["aa"] = 1;
}
else
{
Session["aa"] = ((int) Session["aa"]) + 1;
}
return "Session " + Session["aa"].ToString()
+ " times.";
}
[WebMethod(EnableSession=false)]
public String pqr()
{
if (Application["aa"] == null)
{
Application["aa"] = 1;
}
else
{
Application["aa"] = ((int) Application["aa"])
+ 1;
}
return "Application " +
Application["aa"].ToString() + " times.";
}
}
In the above Web Service, we use
two functions, named abc and pqr. The function abc has a parameter called
EnableSession=true, added to the WebMethod. This parameter switches on the
session tracking. The function pqr is similar to this, with an exception of the
session tracking being disabled. Thereafter, a Session Variable aa, is created
in the function abc and an Application Variable by the same name aa is created
in pqr to store a value. This value is incremented by 1, each time, and is
finally returned as a string.
The Application and Session
objects are framework intrinsic. To understand the above example, select the
'prompt' radio button for the cookie. Now, each time we click on abc, a cookie
is received by the browser. However, such is not the case with the Application.
Now, close all instances of the
browser and open only one browser copy. Rewrite the same URL in the address bar
and click on abc. The session count begins from 1. If you click on pqr, you
will notice that the application remembers its last count, which, it now
increments by 1. By disabling the session support for a particular web
function, the web server now has less work to do. Thus, the web method will be
served up faster.
We first start with the WSDL file
named a.wsdl in the c:\inetpub\wwwroot\bin sub-directory.
a.wsdl
<?xml version="1.0"?>
<definitions
xmlns:s="http://www.w3.org/1999/XMLSchema"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s0="http://tempuri.org/"
targetNamespace="http://tempuri.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema targetNamespace="http://tempuri.org/"
attributeFormDefault="qualified" elementFormDefault="qualified">
<s:element name="abc">
<s:complexType derivedBy="restriction"/>
</s:element>
<s:element name="abcResult">
<s:complexType derivedBy="restriction">
<s:all>
<s:element name="result" type="s:string"
nullable="true"/>
</s:all>
</s:complexType>
</s:element>
<s:element name="string" type="s:string"
nullable="true"/>
</s:schema>
</types>
<message name="abcHttpGetIn"/>
<message name="abcHttpGetOut">
<part name="Body" element="s0:string"/>
</message>
<portType name="zzzHttpGet">
<operation name="abc">
<input message="s0:abcHttpGetIn"/>
<output message="s0:abcHttpGetOut"/>
</operation>
</portType>
<binding name="zzzHttpGet"
type="s0:zzzHttpGet">
<http:binding verb="GET"/>
<operation name="abc">
<http:operation location="/a.html"/>
<input>
<http:urlEncoded/>
</input>
<output>
<text
xmlns="http://microsoft.com/wsdl/mime/textMatching/">
<match name='Title' pattern='TITLE>(.*?)<'/>
<match name='Vijay' pattern='>(.*?)<'/>
</text>
</output>
</operation>
</binding>
<service name="zzz">
<port name="zzzHttpGet"
binding="s0:zzzHttpGet">
<http:address location="http://localhost" />
</port>
</service>
</definitions>
a.html
<HTML>
<HEAD>
<TITLE>Hello!</TITLE>
</HEAD>
<BODY>
<Vijay>Mukhi</Vijay>
</BODY>
</HTML>
We then run the following two
commands:
>wsdl /l:CSharp /n:nnn a.wsdl
The above command creates a file
called zzz.cs for us.
>csc /t:library zzz.cs
This creates a file by the name
of zzz.dll in the bin sub directory.
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.
//
namespace nnn {
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.HttpGetClientProtocol {
[System.Diagnostics.DebuggerStepThroughAttribute()]
public zzz() {
this.Url =
"http://localhost/a.html";
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Web.Services.Protocols.HttpMethodA
ttribute(typeof(System.Web.Services.Protocols.TextReturnReader),
typeof(System.Web.Services.Protocols.UrlParameterWriter))]
public abcMatches
abc() {
return
((abcMatches)(this.Invoke("abc", (this.Url +
"/QuickStart/aspplus/samples/services/TextMatching/CS/MatchServer.html"),
new object[0])));
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public
System.IAsyncResult Beginabc(System.AsyncCallback callback, object asyncState)
{
return
this.BeginInvoke("abc", (this.Url +
"/QuickStart/aspplus/samples/services/TextMatching/CS/MatchServer.html"),
new object[0], callback, asyncState);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public abcMatches
Endabc(System.IAsyncResult asyncResult)
{
return
((abcMatches)(this.EndInvoke(asyncResult)));
}
}
public class
abcMatches {
[System.Web.Services.Protocols.MatchAttribute("TITLE>(.*?)<")]
public string
Title;
[System.Web.Services.Protocols.MatchAttribute(">(.*?)<")]
public string
Vijay;
}
}
a.aspx
<%@ Import Namespace="nnn" %>
<html>
<script language="C#" runat="server">
public void Abc(Object Src, EventArgs E)
{
zzz m= new zzz();
abcMatches ma = m.abc();
ma.Vijay = "mukhi";
Response.Write(ma.Title + "." + ma.Vijay);
}
</script>
<body>
<form runat="server">
<input type="submit" OnServerClick="Abc"
runat="server"/>
</form>
</body>
</html>
Output
After clicking on the button:
Hello!.mukhi
For the first time, we are
creating a WSDL file manually.
<operation name="abc">
<http:operation location="/a.html"/>
We have a tag called operation
that sets the name property to the function abc and the http operation location
is set to a file named a.html.
The text tag encloses two
occurrence of another tag called 'match'. The name 'property' is set to 'Title'
and 'Vijay', respectively. Moreover, a pattern or wild card is specified for
each of them. It specifies a certain pattern or a rule.
Now, the question that vexes our
wits, is : From where will the value of 'Title' be obtained?
The value lies in the html file.
The value of 'Hello', which is enclosed in the Title tag in the HTML file, is
picked up and assigned to the 'Title' variable in a.aspx. The same procedure is
followed for 'Vijay'. The tag name match is a special tag. It is available as a
class called abcMatches, in the aspx file.
In the .cs file that is
generated, the constructor saves the URL in a variable called Url, for future
reference. The function abc returns an instance of the abcMatches class. The
class abcMatches created in zzz.cs, contains two instance variables, 'Title'
and 'Vijay', with or without the pattern.
In the aspx file, when a button
is clicked, the function Abc is called. In this function, we create a new zzz
instance, and then call the function abc from it. The output is an abcMatches
object which we store in an object named ma. Thereafter, the value in 'Vijay'
is initialized to 'mukhi'. Finally, both the variables are displayed, using the
Write function. Thus, without creating any asmx file, using our code, we have
been able to read data within tags in an HTML file. We are thus, doing things
in a way that is a drastic departure from what we have been doing so far.
As we reiterated many times in the past, you are allowed to configure everything in case of ASP+. The main web.config file informs the framework about the aspx file that handles a Web Service, or a file with an asmx extension.