Creating and Consuming .NET Web Services in Five Easy Steps
By Dimitrios Markatos
Published: 11/19/2002
Reader Level: Beginner
Rated: 2.50 by 2 member(s).
Tell a Friend
Rate this Article
Printable Version
Discuss in the Forums

Introduction

The Internet has a new player on the scene that has received a great deal of hype and even some television commercials. They imply that this new next generation technology will change the way business is done on the Web. They demonstrate that companies, their applications or software and any Internet-enabled devices will easily be able to communicate with one another regardless of platform or language, and provide services to each other. Sounds revolutionary! It really is quite exciting. So, what exactly is this, that opens such lines of communication among such diversity? Two words: Web Services, that's what!

Without further ado, let me start off by briefly describing some methods and standards.

Web services give developers the ability to utilize four open web standards:

1. HTTP - Hypertext Transfer Protocol - the standard protocol used over Port 80 that traverses firewalls, which is responsible for requesting and transmitting data over the Internet.
2. SOAP - Simple Object Access Protocol - an XML inherent protocol enclosing a set of rules for data description and process that is the center piece paralleling and complementing the other three mentioned here, with which .NET utilizes nicely with Web Services.
3. XML - Extensible Markup Language - the prominent markup language that all this commonly understood information is written in
4. WSDL - Web Services Description Language - an XML based method use in identifying Web Services and their access at runtime. .NET provides a tool called WSDL.exe which essentially makes it quite easy in generating an XML web service, rather an XML file containing all the methods and instructions the Web Service has, using SOAP as its default btw.

This article will have you creating and consuming a data driven .NET XML Web service in no time flat, with our example providing a list of suppliers to a given country, all in five quick and easy steps!

Incidentally, this article assumes that the reader has a decent grasp in common .NET data access, Web server controls, such a datagrid and some object-oriented programming concepts. If not, don't worry. By doing the examples, and viewing the results, you should have no difficulty in keeping up and observing cause and effect.

Prior to .NET there were other alternatives in accessing a Web service, such as Microsoft's MSXML component, that enabled you to communicate with the given Web Service over HTTP POST. This process however, while acceptable, is just not .NET.

At any rate, let's begin!

Step 1 - Create the Web Service

Begin now by creating the Web service function or method that you'll be exposing, rather calling over the Internet, as you would any object-oriented class. Except incorporate and import all the necessary Web Services namespaces, syntax and attributes, as well as our data namespaces in this case. Since this article in shown in C#, any important differences regarding VB will be shown as well.

So go ahead and copy the code below to suppliers.asmx. Save it to your Inetpub/wwwroot folder, and then run it in your browser, like so: http://localhost/suppliers.asmx. What you'll see is the Web Service Descriptions listed, the Web service name and the exposed method.

By clicking the exposed method link, you'll be presented with the three main protocols available for use. Just so you know, the file with the .asmx extension is the actual Web Service file, that enables the ASP.NET runtime to return the all pertinent exposed web service methods and information.

Code:

<%@ WebService Language="C#" Class="GetInfo" %>

using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Services;

[WebService(Description="My Suppliers List Web Service")]

public class GetInfo : WebService {

[WebMethod(BufferResponse=true)]

public DataSet ShowSuppliers (string str) {

SqlConnection dbConnection = new SqlConnection("server=(local);uid=sa;pwd=;database=Northwind;");

SqlDataAdapter objCommand = new SqlDataAdapter("select ContactName, CompanyName, City, Phone from Suppliers where Country = '" + str + "' order by ContactName asc", dbConnection);

DataSet DS = new DataSet();

objCommand.Fill(DS);

return DS;

dbConnection.Close();
dbConnection = null;

}

}

Quick Explanation:

The <%@ WebService Language="C#" Class="GetInfo" %> directive sets up the file as a Web Service, gives it a name and specifies the language its using.

Aside from your typical data namespace importing, you also add the Web Services namespace.

using System.Web.Services; and in VB it would be - Imports System.Web.Services

Here I've added the [WebService(Description="My Suppliers List Web Service")] which just gives a custom description. Next we create our class which has to be a public class for it to be exposed, and inherit the WebService base class.

public class GetInfo : WebService {

Now we mark the method to be exposed via the WebMethod attribute. Every class enclosed within a Web method get's exposed as a service. Also I add some performance boost by setting the BufferResponse to true.

[WebMethod (BufferResponse=true)]

If you prefer to have the description right below the exposed WebMethod link then you can write this in C#:

[WebMethod (Description="My Suppliers List Web Service",BufferResponse=true)]

The VB version would incorporate the description and BufferResponse in one statement namely just WebMethod, using angle brackets instead. Moreover, this is placed after the class creation and Web service inheriting line, and on the same line with and before the function, like so:

<WebMethod(Description:="My Suppliers List Web Service",BufferResponse:=True)> Public Function _
ShowSuppliers (ByVal str As String) As DataSet

Next, we set up our method or VB function in question, that will accept a string parameter from our drop down list and pass this to our SQL query (you'll see all this in detail in Step 4). If you're really savvy you can pass this and other parameters with the help of C# structs (scaled down classes) to enumerate your data value types, and provide you with better memory allocation. But for now we'll stick to basics like so:

public DataSet ShowSuppliers (string str)

Above we set up our dataset method to return us exactly that. Lastly, we perform typical data connection and access and return our results. And we're done! So far so good? After viewing this in your browser, the above code should to start to make some more sense by now. Let's go to Step 2.

Step 2 - Consume the Web Service Source file

Next append ?WSDL to the web services URI (Uniform Resource Identifier) like so - http://localhost/suppliers.asmx?WSDL. What's this you ask? This is the WSDL document that is exactly what the client will use to access this service.

Even so, you don't have to know much about this unreadable code to produce results, which is where the WSDL.exe command-line tool comes to the rescue. Due to Web services open protocol nature, this tool further enables you to consume non-.NET Web Services as well.

You can bypass WSDL and test the XML results instantly through HTTP GET protocol, by typing in your browser - http://localhost/suppliers.asmx/ShowSuppliers?str=USA which passes USA as a parameter to the ShowSuppliers class method. Note: If you're using .NET SDK Beta 1.1 (v.1.1.4322), it seems to prefer HTTP POST protocol, so invoke the Web Service through its exposed method link. The XML results? A little crazy huh? Nevertheless, scroll down a little and you'll see the query results of our class call. Later in Step 4, all this gooblygook will make much more readable sense.

So to create our proxy class sourcefile, make a batch file named makeWS.bat and type in:

[C#]

wsdl.exe /l:CS /n:WService /out:bin/GetSuppliers.cs http://localhost/suppliers.asmx?WSDL

[VB]

wsdl.exe /l:VB /n:WService /out:bin/GetSuppliers.vb http://localhost/suppliers.asmx?WSDL

pause

This tells our WSDL tool:

/l: is the language your using. /n: creates the WService namespace so you could reference it from your .aspx page, and finally send the C#/VB source file to the bin folder from which we'll create our dll assembly to use in Step 3. Also add pause, so after this is all said and done, you'll be prompted to press any key to continue, rather more importantly knowing for sure all went according to plan.

So, now locate your new batch file and double-click on it to run it. Once you have done this, you will have created, rather consumed, the proxy class or source file GetSuppliers.cs right from the .asmx file. Have a look in your bin folder.

Note: You could run these commands via the command-line prompt, but for convenience sake, I prefer the good old batch file. Just for blanks and giggles, you may be wondering where the phrase consuming came about? In this regard, it simply means you're presenting the Web Service to the "consume"r. Get it?


Step 3 - Build Our Object

OK, now let's invoke the .NET C# compiler (csc.exe) or VB compiler (vbc.exe) to convert your source file into an assembly or DLL by creating a new .bat file named makelib.bat and typing in:

[C#]

csc /t:library /out:bin\GetSuppliers.dll bin\GetSuppliers.cs /reference:System.dll,System.Data.dll,System.Web.dll,System.Web.Services.dll,System.XML.dll /optimize

[VB]

vbc /t:library /out:bin\GetSuppliers.dll bin\GetSuppliers.vb /reference:System.dll,System.Data.dll,System.Web.dll,System.Web.Services.dll,System.XML.dll /optimize

pause

All this says is to compile the source file from the bin folder to a DLL of set name, to the bin folder. The /t:library instructs the compiler to create a dll (dynamic link library), rather than an exe (executable) file, with /reference: importing the necessary dll's libraries used in our Web service. Finally, we /optimize our dll to produce smaller, faster, more efficient output.

Step 4 - Put it All Together

Now copy and paste the code below to an .aspx .NET page and name it. The code below is the page that will access the assembly/DLL in your bin folder, and with all the web server controls to pass the appropriate parameters to the Web Service. Go ahead and run it (ex. http://localhost/websrvce.aspx), and I'll break it down for you in a sec.

The Code:

<%@ Page Language="C#" Explicit="true" Strict="true" Buffer="true"%>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="WService" %>

<html>
<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs e) { Response.Flush();}

void SubmitBtn_Click (object src, EventArgs e){

int RcdCount;
string Catg = DropDown1.SelectedItem.Text;

//Instantiate DLL
GetInfo supInfo = new GetInfo();

//Pass parameter into DLL function
DataSet MyData = supInfo.ShowSuppliers(Catg);

MyDataGrid.DataSource = MyData.Tables[0].DefaultView;
MyDataGrid.DataBind();

RcdCount = MyData.Tables[0].Rows.Count;

if (RcdCount <= 0) {

Message.InnerHtml = "<b>No results were found for <FONT Color=Red><i>"+ Catg +"</i></font>";

MyDataGrid.Visible = false; //Hide Results until needed

}else{

Message.InnerHtml = "<b><FONT Color=Red><i>" + Catg + "</i></font> has " + RcdCount + " local suppliers</b>";
MyDataGrid.Visible = true;
}

}

</script>
<body style="font: 10pt verdana">

<h4>Accessing Data with Web Services</h4>

<form runat="server">

<asp:DropDownList id=DropDown1 runat="server">
<asp:ListItem>Australia</asp:ListItem>
<asp:ListItem>Brazil</asp:ListItem>
<asp:ListItem>Canada</asp:ListItem>
<asp:ListItem>Denmark</asp:ListItem>
<asp:ListItem>Finland</asp:ListItem>
<asp:ListItem>France</asp:ListItem>
<asp:ListItem>Germany</asp:ListItem>
<asp:ListItem>Italy</asp:ListItem>
<asp:ListItem>Japan</asp:ListItem>
<asp:ListItem>Netherlands</asp:ListItem>
<asp:ListItem>Norway</asp:ListItem>
<asp:ListItem>Singapore</asp:ListItem>
<asp:ListItem>Spain</asp:ListItem>
<asp:ListItem>Sweden</asp:ListItem>
<asp:ListItem>UK</asp:ListItem>
<asp:ListItem>USA</asp:ListItem>
</asp:DropDownList>
<asp:button text="Submit" OnClick="SubmitBtn_Click" runat=server/>
<p>
<span id="Message" runat="server"/>

<p>


<ASP:DataGrid id="MyDataGrid" runat="server"
AutoGenerateColumns="True"
Width="100%"
BackColor="White"
Border="1"
BorderWidth="1"
CellPadding="1"
CellSpacing="1"
Font-Size="10pt"
HeaderStyle-BackColor="White"
HeaderStyle-ForeColor="Blue"
AlternatingItemStyle-BackColor="White"
AlternatingItemStyle-ForeColor="Black"
ShowFooter="false"
/>

</form>

</body>
</html>


How It Works:

Pretty cool? Now aside from the common data accessing, and Web server control usage, I'll outline some specifics. By virtue of creating our proxy class in Step 2 with a namespace, we need to import it the dll we created in Step 3.

<%@ Import Namespace="WService" %>

We instantiate it or reference our object with:

[C#]

GetInfo supInfo = new GetInfo();

[VB]

Dim supInfo As New WService.GetInfo()

which is our Web Service class. We then retrieve our dropdown list parameter and pass is to our ShowSuppliers constructor method like so:

[C#]

string Catg = DropDown1.SelectedItem.Text;

DataSet MyData = supInfo.ShowSuppliers(Catg);

[VB]

Dim Catg As String = DropDown1.SelectedItem.Text

Dim MyData As DataSet = supInfo.ShowSuppliers (Catg)

And the rest? Just common .NET stuff, which I've assumed the reader to kind of understand. Nevertheless, it shouldn't be to hard to follow or figure out. The .NET documentation and Quickstart Tutorials will help will plenty more information.

Well, guess what? We're completely done!

Step 5 - Show it Off

Congratulations are in order, for you have now built your first full fledged .NET XML Data Web Service in no time flat, without any IDE program such a VS.NET I might add, and only using something as simple as Notepad. Now can anyone really say this was a big, difficult ordeal? I didn't think so.

Additionally, if you're wondering, OK now I have a cool Web service. How will anyone else "discover" it? Well, exactly, you're right. What? Yeah, absolutely. Just kidding, with XML Web service "discovery", you can advertise your Web service and expose its location and other information, alongside a .discomap file providing links to these files.

XML Web Service discovery or DISCO for short is Microsoft's Web Services Discovery tool which "discovers" the URL for a Web Service and saves that information in a file on your local server.

Here's how:

disco http://localhost/suppliers.asmx?DISCO

This created a static discovery file with a WSDL file with all important information pertaining to your Web Service, again providing you want to advertise. Opposite this static discovery file is a dynamic discovery .vsdisco file which notes all available Web Services located within that URL.

Remember in Step 2, the WSDL command for creating the source file with "?WSDL"? Now for an already "discovered" file you can use:

wsdl.exe /l:CS /n:WService /out:bin/GetSuppliers.cs http://localhost/suppliers.wsdl

to create your source file and in turn, your DLL for Web Service access.

When you examine the created .disco file you'll notice the follwing information,

<contractRef ref="http://localhost/suppliers.asmx?wsdl" docRef="http://localhost/suppliers.asmx" xmlns="http://schemas.xmlsoap.org/disco/scl/" />

which contains the link to your Web Service so others could discover it, alongside XSD schemas, and service descriptions. By this information others can parse the WSDL document, and build a proxy source file and implement this Web Service locally!

If you do have something you'd like to share, run over to the Microsoft UDDI (Universal Description, Discovery and Integration) Business Registry (UBR) node - http://uddi.microsoft.com/, which is currently supported by Microsoft, IBM and Ariba. Here you can find other available Web Services and any details, register your Web Service or discover more about this whole business.


A Little Asynchronous"ity"

Before, I conclude this article; I need to mention an additional method of calling Web Services from your application. Web Services by default form are called synchronously. As a result, both the application and its inherent Web Service will have to finish simultaneously, whereby one possibly quicker method within the application will have to wait for the other slower one to first finish, before the application can fully display its results, potentially creating an unnecessary delay to the client. Likewise, since Web Service calls make use of Port 80 for communications, they can at times cause this type of delay. Therefore, how would one be able to remedy such a situation? With a little Asynchronous"ity", of course.

There four common ways to make asynchronous method calls. Here we will demonstrate waiting for our asynchronous call utilizing the WaitHandle method which determines when the service call is complete. The other three possible methods for asynchronous calls include:

1) The IsCompleted property of the IAsyncResult returned by BeginInvoke, within our BeginSuppliers Method
2) Executing a callback method when the asynchronous call finishes
3) Finally, parallel any processing or code until the call completes prior to calling EndInvoke

So given that Asynchronous calls can perform a given task, without affecting other functions around them, let's implement our chosen technique. Going back to Step 2, you'll remember how we created our proxy class file for our .asmx Web Service file. If you actually took the time to inspect it, you will have noticed aside from our main ShowSuppliers Dataset function, two additional functions were listed below it - BeginShowSuppliers and EndShowSuppliers. These are the Asynchronous functions that will enable us to produce Asynchronous Web Service calls implementing the WaitHandle Classes WaitOne() Method, and here's how:

We do all this from our .aspx page we created in Step 4. Here's all the additional code:

//Instantiate DLL
GetInfo supInfo = new GetInfo();

// Begin the Asynchronous call to ShowSuppliers
IAsyncResult AsyncWS = supInfo.BeginShowSuppliers(Catg, null, null);

//We wait for the callback
AsyncWS.AsyncWaitHandle.WaitOne();

//We return the data bypassing the initial ShowSuppliers Method
DataSet MyData = supInfo.EndShowSuppliers(AsyncWS);

Notice, just a few more lines of code were added. The only thing that changed is that we added our asynchronous methods right after we instantiated our dll. After this is where we create an instance of our IAsyncResult object that will let us know when the Web Service process has finished.

IAsyncResult AsyncWS = supInfo.BeginShowSuppliers(Catg, null, null);

Here above, we called the asynchronous BeginShowSuppliers method that accepts our initial dropdown list parameter and two other mandatory arguments which, in this example, were not included, and were substituted with null. The second argument would typically call the ASyncCallBack object responsible for calling another method once the BeginShowSuppliers completes, contrary to our example. The third argument would contain information about the asynchronous operation.

We then next implement the AsyncWaitHandle that handles and allows us to incorporate different kinds of synchronization techniques. There are a few AsyncWaitHandles available to us. With the WaitOne method in our line below, we wait for the WaitHandle to receive a callback signal. Further available methods include: WaitAll(), that waits for all elements to receive a callback signal, and WaitAny(), which waits for any one of the elements to receive a callback signal, both utilizing specified arrays as one the overloaded element arguments, alongside an Integer for specific time interval waiting and, or Timespan as well. In any event, all WaitHandles have multiple overload forms available to them that can be further viewed in the .NET SDK documentation.

//We wait for the default callback
AsyncWS.AsyncWaitHandle.WaitOne();

Quick digression regarding the line above: Although our WaitOne method as shown, in default form will work fine, it can be overloaded. In illustrating, our WaitOne Handler once overridden in a derived class will block the current thread until the current WaitHandle receives a signal. The two arguments it allows, paralleling what the other two Wait methods also accept, are: 1) waiting a set amount of milliseconds to pass, and 2) a Boolean value, true or false specifying whether to exit the synchronization domain before the wait.

Once the waiting is over, we return our results via the EndShowSuppliers method that got the OK from the WaitHandle. The AsyncWaitHandle method being a resource releaser, OK'ed our supInfo.EndShowSuppliers method below, and in turn obtained our data, while the rest of our application didn't grow impatient.

//We return the data
DataSet MyData = supInfo.EndShowSuppliers(AsyncWS);

Therefore, in coping with the possible speed limitations allotted us via HTTP network traffic, we can implement our Web Service without any concern the rest of our application will wait impatiently until all is completed. With some Asynchronous"ity,  our application will run its entire course, in conjunction with our possibly leisurely Web Service, simply jumping in when it's finished.

In summing up, our BeginShowSuppliers method once initialized returns instantly to notify (though not in this case - we use the WaitHandler) your applicable callback function that the process is done, and it's OK to call the EndShowSuppliers method and return the results.

And there you have it, a quick look at Asynchronous Web Services. As you may have wondered, yes, this can get far more complex than what was just aforementioned. Nevertheless, with the amount you have learned now, it should be a little less intimidating.


Conclusion

So, not that bad, huh? Realizing how fast you could create a nice, functional .NET XML Data Web Service, and even an Asychronous one to boot, should've put a smile on your face.

Additionally, be sure to explore all the .NET documentation for greater detail on all presented here for additional tweaking, implementing error handling, security, caching, and few other things to keep in mind when creating and consuming Web Services. Even so, there's plenty of stuff in the .NET documentation and online going into more detail about all this.

Therefore, with all aforementioned, it's really quite easy creating and consuming your own web services, or discovering and consuming other available ones over the Internet and utilized them as if those applications reside on your local server! I tell ya, with each passing moment .NET reveals itself a more truly amazing and extremely powerful platform.

Until Next Time, Happy .NETing </>



Marketplace
(Sponsored Links)
What are the green links?
   



 
Copyright © 2007 CMP Tech LLC |
Privacy Policy (4/10/06) | Your California Privacy Rights (4/10/06) | Terms of Service | Advertising Info | About Us | Help