Web Services: Basics and Beyond Part 2

Introduction

A young woman went to her doctor complaining of pain." Where are you hurting?" asked the doctor." You have to help me, I hurt all over", said the woman." What do you mean, all over?" asked the doctor, "be a little more specific." The woman touched her right knee with her index finger and yelled, "Owe, that hurts." Then she touched her left cheek and again yelled, "Ouch! That hurts, too." Then she touched her right earlobe, "Owe, even THAT hurts", she cried.
The doctor checked her thoughtfully for a moment and told her his diagnosis; "You have a broken finger".

Sometimes the solution to a complex problem can be so simple. Similarly Web Services &.Net solve a lot of the problems of the past like DLL Hell, Versioning, Communication across Firewall and Communication across platforms etc., Having discussed the significant concepts about web services in the last part it is time to move on and learn about creating them productively. This part shall demonstrate how a simple web service can be created quickly using Visual Studio.Net. Then we shall discuss the actual steps that are part of a web service execution. Then we shall go through a demonstration that builds an exotic web service and different clients to access it. Finally we shall conclude with a discussion on Global XML Web Services Architecture and the newly introduced DIME format.

A Web Service Architecture



BasBeyP2WebSer1.gif

A Simple Web Service Demo using VS.Net

The screen shots below show the steps involved in creating a Simple Web Service.  

BasBeyP2WebSer2.jpg

Step 1:

Launch Visual Studio.NET, select File menu and select New -> Project .  The New project Dialog box will pop up. Select  Visual C# projects  and  ASP.NET Web Service Templates as shown above.  

BasBeyP2WebSer4.jpg

Step 2:

Once you select and hit ok VS.NET will connect to Web Server (IIS), and it will create a virtual directory in the name of the project as shown above. 

Step 3:

From the solution explorer select Service1.asmx as shown above and add the WebMethod attribute as shown below. This attribute exposes the function over the web.  

BasBeyP2WebSer5.jpg

Step 4:

A method called GetServerTime is added to the code. Once this method is added, hit F5 to compile. This will launch the Test Page for the web service we just created.  As shown below

BasBeyP2WebSer6.jpg



Step 5:

When you hit Invoke button this calls the web service using HTTP-GET, and displays the result as (SOAP message) XML, which is shown below.

BasBeyP2WebSer8.jpg

Web Service at Work

Before we proceed further it is desirable to know about the various steps involved when a web service serves a client.

The client uses a web service proxy class to invoke the web service. The proxy class is generated by a toolkit (IBM toolkit or the Visual Studio.Net) depending on the type of client. The tool kit uses the WSDL file to generate the proxy.

Having generated the proxy the client instantiates the proxy and invokes the web method available in the web service. When this happens the arguments of the web method are formatted as a SOAP request and then sent over the network to the web service. This process is called Serialization.

On the server side the web method arguments are extracted from the SOAP request. This process is called Deserialization.

Then an object of the actual web service class is instantiated on which the web method is invoked passing in the extracted arguments. Then the web method executes and sets the return values.

The return values are then serialized into a SOAP response and then sent back to the client over the network.

The client deserializes the soap response and uses the return values.

An Exotic Service and Smart Clients

Let us now attempt to create a full-fledged web service and various clients to access it. Let us assume that a telecommunications company hosts the Web Service. The service provides information about its cell phone plans.

The Plan Information Service

The Web Service basically provides plan information through a web method "GetAllProviderCellPhonePlans". The method opens the database, retrieves the plan information, fills a dataset and returns it. The web service screen shot and its code are shown below.

BasBeyP2WebSer9.jpg

BasBeyP2WebSer10.jpg

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.Data.SqlClient ;
namespace ManiService
{
/// <summary>
/// Summary description for Service1.
/// </summary>
public class Service1 : System.Web.Services.WebService
{
public Service1()
{
//CODEGEN: This call is required by the ASP.NET Web Services Designer
InitializeComponent();
}
[WebMethod]
public string getGreetings()
{
return "Welcome to the world of Web Services.";
}
#region Component Designer generated code
//Required by the Web Services Designer
private IContainer components = null;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
// WEB SERVICE EXAMPLE
// The HelloWorld() example service returns the string Hello World
// To build, uncomment the following lines then save and build the project
// To test this web service, press F5
// [WebMethod]
// public string HelloWorld()
// {
// return "Hello World";
// }
[WebMethod(Description="This Method provided Cell phone plans")]
public DataSet GetAllProviderCellPhonePlans()
{
SqlConnection Con;
string sConstring;
string sSQL;
sConstring="user id=sa;password=sa;database=Sreenidotnet;server=localhost";
sSQL ="select * from CellPhoneplan";
Con =
new SqlConnection(sConstring);
DataSet ds =
new DataSet();
Con.Open();
SqlDataAdapter da=
new SqlDataAdapter(sSQL,Con);
da.Fill(ds,"cellPhonePlans");
return ds;
}
}
}

As we know, Web Services are invoked through a SOAP Request and they return results through a SOAP Response.

A sample SOAP request and response are shown below. The placeholders shown need to be replaced with actual values.

Request

<?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>
<
GetAllProviderCellPhonePlans xmlns="http://tempuri.org/" />
</
soap:Body>
</
soap:Envelope>

Response

<?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>
<
GetAllProviderCellPhonePlansResponse xmlns="http://tempuri.org/">
<
GetAllProviderCellPhonePlansResult>
<
xsd:schema>schema</xsd:schema>xml</GetAllProviderCellPhonePlanResult>
</
GetAllProviderCellPhonePlanResponse>
</
soap:Body>
</
soap:Envelope>

A Windows Client

Now let us look at a windows client that uses our web service.

First Add Web Reference to the windows client project. This can be done Right clicking on project Reference. (As shown below)



Windows Client Accessing GetAllProviderCllPhonePlans

The code for the windows client is shown below:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using WSClient.localhost; //Add the Reference to this client project
namespace WSClient
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.DataGrid dataGrid1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.dataGrid1 = new System.Windows.Forms.DataGrid();
((System.ComponentModel.ISupportInitialize)(
this.dataGrid1)).BeginInit();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(256, 272);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(128, 23);
this.button1.TabIndex = 0;
this.button1.Text = "GetCellPhonePlan";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// dataGrid1
//
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(24, 16);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(632, 232);
this.dataGrid1.TabIndex = 1;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(664, 326);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.dataGrid1,
this.button1});
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(
this.dataGrid1)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(
new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
DataSet PlanDetails ;
// Create Instance of Dataset
WSClient.CellPhonePlanService.Service1 PhoneWS = new WSClient. CellPhonePlanService.Service1(); // Create Instance of CellPhonePlanService
PlanDetails =PhoneWS.GetAllProviderCellPhonePlans();
//Call the WebMethod this returns DataSet
dataGrid1.DataSource= PlanDetails; // Resultant DataSet Bind to DataGrid
}
}
}

The output shown by the client is shown below:

Output

BasBeyP2WebSer12.jpg

A Java Client

A Java client can access a .Net based web service through a proxy. IBM Web Services toolkit can be used to generate a proxy using the WSDL file for the web service. Let us assume that we have generated a proxy "PlanInfoProxy" using the IBM Web Services toolkit. For details on use of the IBM toolkit refer to the IBM website. The next step would be to tell the proxy how to extract the returned type in our case, the "DataSet" type. Apache provides a number of classes to deserialize the SOAP message and extract the actual information. The code for deserialization should be inserted next into the proxy. In our case let us assume that our proxy parses the message and returns the plan info to us as a string. Then the proxy can be compiled and is ready to be used in the actual client. The piece of code below shows how a java client would use the generated proxy to call our web service.

import java.io.*
/* Web Service client */
public class PlanInfoRetriever
{
private String retrievePlans()
throws org.apache.soap.SOAPException
{
/*Instantiate the Web Service Proxy generated by the IBM web services tool kit*/
PlanInfoProxy pInfo = new PlanInfoProxy();
return pInfo.GetAllProviderCellPhonePlan();
}
private void displayPlanInformation(String planInfo)
{
/*Write Code to Display the Cell Phone Plans here*/
}
public static void main(String args[])
{
try
{
/*Retrieve Plans*/
String pI = pInfo.GetAllProviderCellPhonePlan();
/* Display Cell Phone Plans */
DisplayPlanInformation(pI);
}
catch (org.apache.soap.SOAPException exc)
{
/*handle exception*/
}
}
}

The classes thus created can be compiled and then executed to access our plan information service.

Word of the Wind: GXA & DIME

This is the right moment to learn about two path-breaking concepts namely GXA and DIME.

Baseline XML Web Services Specifications

  • SOAP
  • UDDI
  • WSDL

Global XML Web Services Specifications

  • WS-Inspection
  • WS-License
  • WS-Referral
  • WS-Routing
  • WS-Security

GXA stands for Global XML Web Services Architecture. This is Based on Base line WebServices. In our company we started an effort in our project office for creating a repository of reusable objects that can be plugged into similar projects. For example we created a role-based-security mechanism that can be reused in all XML Web Service based servers. But implementations like these may sometimes tend to be non complimentary to the basic objectives of XML Web Services. So a need for a baseline specification was felt. The GXA is a step in that direction by Microsoft. Some of the specifications in GXA are WS-Inspection, WS-License, WS-Security etc., For example WS-Inspection is used for browsing UDDI as mentioned in the previous article. There are four important characteristics that make the GXA more powerful. GXA is modular meaning it consists of modular elements that can be combined together as needed, it is general purpose, federated (fully distributed, requires no admin), and standards based.

DIME stands for Direct Internet Message Encapsulation mechanism and is used for packaging data in binary format inside SOAP messages. Data does not always come on as XML in SOAP messages. Sometimes huge data/image files need to be transferred across the network. In such cases serializing data into XML format might not be good in terms of performance. DIME comes in handy in these situations. Also communications between legacy systems may be done with DIME eliminating the need for separate serialization architecture on both sides. Many of us may already be aware of the MIME (Multi-purpose Internet Mail Extensions) specification. DIME offers a performance advantage over the MIME specifications in the following area: To extract data from the middle of a MIME message we need to scan the message through all the rows of data before the data of interest is reached. In DIME however the headers can be scanned to reach the appropriate row.

A complete discussion of GXA and DIME warrants a separate article.

Conclusion

In this part we painted a programmatic picture of the web services. The next part of this article shall deal with the data access side of web services, shall have a brief interlude with ADO.Net and shall talk much more. Ride with us pals! Let's go on with our guns blazing!

Hurrah!


Similar Articles