Windows Systems Programming: Spring 2004

[ Home | Syllabus | Course Notes | Assignments | Search]


Web Services

Internet for computers not people.
Based on existing and emerging standards:

Can be implemented using many current Internet pieces (web servers, protocols)

Remember the "calc" example (our first WebForm) - that was for users who wanted to add two numbers and used the web form for data entry.

But what is a program wanted to Add two numbers

For example

This example adds 2 and 2:

POST /calc.asmx HTTP/1.1
Host: www.wintellect.com
Content-Type: text/xml; charset=utf-8
Content-Length: 338
SOAPAction:  "http://tempuri.org/Add"

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

And here’s how the Web service would respond:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 353

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

//// also supported is the GET method

GET /calc.asmx/Add?a=2&b=2 HTTP/1.1
Host: www.wintellect.com

The Web service responds as follows:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 80

<?xml version="1.0" encoding="utf-8"?>
<int xmlns="http://tempuri.org/">4</int>

//// Or alternatively

POST /calc.asmx/Add HTTP/1.1
Host: www.wintellect.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

a=2&b=2

And here’s the Web service’s response:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 80

<?xml version="1.0" encoding="utf-8"?>
<int xmlns="http://tempuri.org/">4</int>

Web Services Example

Calc.asmx
<%@ WebService Language="C#" Class="CalcService" %>

using System;
using System.Web.Services;

[WebService (Name="Calculator Web Service",
    Description="Performs simple math over the Web")]
class CalcService
{
    [WebMethod (Description="Computes the sum of two integers")]
    public int Add (int a, int b)
    {
        return a + b;
    }

    [WebMethod
        (Description="Computes the difference between two integers")]
    public int Subtract (int a, int b)
    {
        return a - b;
    }
}

Testing asmx applications

For Example

Suppose web services is available at "http://128.82.4.94:8000/cwild/Book1/Chap11/Calc/Calc.asmx"
Putting this URL in a IE browser would give this window


WSDL

This XML file is the key to making the above work - here is the WSDL for the above web service (obtained by clicking the "Service Description" above

<?xml version="1.0" encoding="utf-8" ?>
- ...
- <types>
- <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
- <s:element name="Add">
- <s:complexType>
- <s:sequence>
  <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int" />
  <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int" />
  </s:sequence>
  </s:complexType>
  </s:element>
- <s:element name="AddResponse">
- <s:complexType>
- <s:sequence>
  <s:element minOccurs="1" maxOccurs="1" name="AddResult" type="s:int" />
  </s:sequence>
  </s:complexType>
  </s:element>

  </types>

- <message name="AddHttpGetIn">
  <part name="a" type="s:string" />
  <part name="b" type="s:string" />
  </message>
- <message name="AddHttpGetOut">
  <part name="Body" element="s0:int" />
  </message>
 

 <portType name="Calculator_x0020_Web_x0020_ServiceSoap">

- <operation name="Add">
  <documentation>Computes the sum of two integers</documentation>
  <input message="s0:AddSoapIn" />
  <output message="s0:AddSoapOut" />
  </operation>
 
 

- <service name="Calculator_x0020_Web_x0020_Service">

  <documentation>Performs simple math over the Web</documentation>
- <port name="Calculator_x0020_Web_x0020_ServiceSoap" binding="s0:Calculator_x0020_Web_x0020_ServiceSoap">
  <soap:address location="http://192.168.1.104/cs477/Chap11/Calc/Calc.asmx" />
  </port>
- <port name="Calculator_x0020_Web_x0020_ServiceHttpGet" binding="s0:Calculator_x0020_Web_x0020_ServiceHttpGet">
  <http:address location="http://192.168.1.104/cs477/Chap11/Calc/Calc.asmx" />
  </port>
- <port name="Calculator_x0020_Web_x0020_ServiceHttpPost" binding="s0:Calculator_x0020_Web_x0020_ServiceHttpPost">
  <http:address location="http://192.168.1.104/cs477/Chap11/Calc/Calc.asmx" />
  </port>
  </service>
  </definitions>

The WebMethod Attribute

Parameter Name

Description

BufferResponse

Enables and disables response buffering

CacheDuration

Caches responses generated by this method for the specified number of seconds

Description

Adds a textual description to a Web method

EnableSession

Enables and disables session state for this Web method

MessageName

Specifies the Web method’s name

TransactionOption

Specifies the transactional behavior of a Web method

[WebMethod (CacheDuration="10")]
public string GetCurrentTime ()
{
    return DateTime.Now.ToShortTimeString ();
}
class CalcService : WebService
{
    [WebMethod (EnableSession="true",
        Description="Adds an item to a shopping cart")]
    public void AddToCart (Item item)
    {
        ShoppingCart cart = (ShoppingCart) Session["MyShoppingCart"];
        cart.Add (item);
    }
}

Web Services and Complex Data Types

  • Possible because relies on XML which can represent almost any complex type

  • Uses System.Xml.Serialization.XmlSerializer class

  • XML Schema allows "rehydrating" of the object

Consider the example
Locator.asmx
<%@ WebService Language="C#" Class="LocatorService" %>

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

[WebService (Name="Bookstore Locator Service",
    Description="Retrieves bookstore information from the Pubs database")]
class LocatorService
{
    [WebMethod (Description="Finds bookstores in a specified state")]
    public Bookstore[] FindStores (string state)
    {
        return FindByState (state);
    }

    Bookstore[] FindByState (string state)
    {
        SqlDataAdapter adapter = new SqlDataAdapter
            ("select * from stores where state = \'" + state + "\'",
            "server=localhost;database=pubs;uid=sa;pwd=");
        DataSet ds = new DataSet ();
        adapter.Fill (ds);

        DataTable table = ds.Tables[0];
        Bookstore[] stores = new Bookstore[table.Rows.Count];

        for (int i=0; i<table.Rows.Count; i++) {
            stores[i] = new Bookstore (
                table.Rows[i]["stor_name"].ToString ().TrimEnd
                    (new char[] { ' ' }),
                table.Rows[i]["stor_address"].ToString ().TrimEnd
                    (new char[] { ' ' }),
                table.Rows[i]["city"].ToString ().TrimEnd
                    (new char[] { ' ' }),
                table.Rows[i]["state"].ToString ().TrimEnd
                    (new char[] { ' ' })
            );
        }
        return stores;
    }
}

public class Bookstore
{
    public string Name;
    public string Address;
    public string City;
    public string State;

    public Bookstore () {}

    public Bookstore (string name, string address, string city,
        string state)
    {
        Name = name;
        Address = address;
        City = city;
        State = state;
    }
}

 

The schema is obtained from the WSDL generated by .NET

<s:complexType name="ArrayOfBookstore">
  <s:sequence>
    <s:element minOccurs="0" maxOccurs="unbounded"
      name="Bookstore" nillable="true" type="s0:Bookstore" /> 
  </s:sequence>
</s:complexType>
<s:complexType name="Bookstore">
  <s:sequence>
    <s:element minOccurs="1" maxOccurs="1" name="Name"
      nillable="true" type="s:string" /> 
    <s:element minOccurs="1" maxOccurs="1" name="Address"
      nillable="true" type="s:string" /> 
    <s:element minOccurs="1" maxOccurs="1" name="City"
      nillable="true" type="s:string" /> 
    <s:element minOccurs="1" maxOccurs="1" name="State"
      nillable="true" type="s:string" /> 
  </s:sequence>
</s:complexType>
  • This prevents the use of Get/Post methods unless the payload is XML
 

 

 

 


Copyright chris wild 1999-2004.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: March 01, 2004.