Section 7.6.  Web Services

JavaScript Editor Free JavaScript Editor     JavaScript Debugger 




Main Page

Previous Page
Next Page

7.6. Web Services

Regardless of where you look, web services are a hot subject, and not just on resumés. Something of a mystique surrounds web services; like the latest hot video game, everybody wants one, even if nobody is quite sure what one is. Ah, to be a kid again, wanting something just because I want it. Who am I kidding? I'm still that way, obsessing over games such as Stargate: The Alliance for XBox, and books such as Practical Guide to Red Hat Linux: Fedora Core and Red Hat Enterprise Linux. However, unlike businesses, my pockets aren't full of much other than lint, which means that I have to wait, whereas businesses can just whip out the checkbook.

7.6.1. What Is a Web Service?

Alright, because everybody wants a web service, there are only two questions. The first question is, what is a web service? And the second question is, how does a web service work? Let's start by answering the first question: What is a web service?

A web service is a piece of software designed to respond to requests across either the Internet or an intranet. In essence, it is a program that executes when a request is made of it, and it produces some kind of result that is returned to the caller. This might sound a lot like a web page, but there is a significant difference: With a web page, all the caller is required to know about the page is the URI. With a web service, the caller needs to know both the URI and at least one of the web service's public methods. Consider, for example, the C# web service shown in Listing 7-5. Knowing the URI, which, incidentally, is http://localhost/AJAX4/myService.asmx, isn't enough. It is also necessary to know that the public method is called monster.

Listing 7-5. Web Service Example

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;

namespace AJAX4
{
  public class myService : System.Web.Services.WebService
  {
    public myService()
    {

      InitializeComponent();
    }

    #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

    [WebMethod]
    public string monster()
    {
      return "Grrr!";
    }
  }
}

Great, now we have a web servicewhoopee, we're done, right? Wrong! Having a web service is only part of the battle; it falls into the same category as having a swimming pool and not knowing how to swim. Yeah, it is impressive, but deep down, there is a nagging feeling of feeling stupid for the unnecessary expense. What is needed is the knowledge of how to invoke the web service.

Impressive word, invoke; it conjures up images of smoke, candles, pentagrams, and demons, the kind that could rip a soul from a body and torment it for eternityor, at least, during the annual performance evaluation. As with invoking a demon, invoking a web service is all a matter of how things are phrased, knowing both what to ask and how to ask. In both cases, mistakes can lead to, um, undesirable results.

7.6.2. SOAP

Unlike demonology, which requires the use of Latin (of the Roman variety, not the swine variety), invoking a web service requires the use of a dialect of XML called SOAP. And as with everything even remotely computer related, SOAP is an acronym standing for Simple Object Access Protocol. Fortunately, with SOAP, the little elves who name things didn't lie: It is actually simple, and who would have thought it?

The basic structure of a SOAP request is an envelope, which is also a pretty good analogy of not only what it is, but also what it does. It serves as a wrapper around the request and any parameters being passed to the web service. Consider the example of SOAP shown in Listing 7-6, whose purpose is to invoke the web service from Listing 7-5.

Listing 7-6. SOAP to Invoke the Web Service

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

Doesn't look like much does it? All that the SOAP envelope does is specify the method, monster, along with a namespacewhich, in this case, is the default, basically a placeholder. If the method requires any parameters, they would be passed as children of that method. For example, let's add the method shown in Listing 7-7 to the web service from Listing 7-5.

Listing 7-7. Method to Add to the Web Service

[WebMethod]
public string echo(string text)
{
  return text;
}

Beyond changing the method from monster to echo, there is the little problem of the parameter named text. Because of the parameter, it is necessary to change the body of the SOAP request to the one shown in Listing 7-8..

Listing 7-8. The New SOAP 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>
    <echo xmlns="http://tempuri.org/">
      <text>Dijon Ketchup</text>
    </echo>
  </soap:Body>
</soap:Envelope>

Now that we've got the basics down of the SOAP envelope (yes, there is more) let's consider how to deliver it to the web service. Unfortunately, FedEx and UPS are both out of the question, although it might be fun to call and ask the rates for delivering a SOAP envelope to a web serviceat least, until they got a restraining order. This leaves the XMLRequest object as the best available resource: neither rain, nor snow, and all that stuff.

Everything necessary to deliver the SOAP envelope is already in there, so the only issue is how to send our SOAP envelopeafter all, there are no mailboxes with little red flags. Fortunately, we have a good chunk of the code down already, including the SOAP envelope itself. Instead of beating around the bush, Listing 7-9 shows the client-side JavaScript necessary to invoke the monster method of our web service.

Listing 7-9. JavaScript to Invoke the monster Method

try {
  objXMLHTTP = new XMLHttpRequest();
}
catch(e) {
  objXMLHTTP = new ActiveXObject('Microsoft.XMLHTTP');
}

objXMLHTTP.onreadystatechange = asyncHandler;

objXMLHTTP.open('POST', 'http://localhost/AJAX4/myService.asmx', true);
objXMLHTTP.setRequestHeader('SOAPAction','http://tempuri.org/monster');
objXMLHTTP.setRequestHeader('Content-Type','text/xml');
objXMLHTTP.send(soap);

function asyncHandler() {
  if(objXMLHTTP.readyState == 4)
    alert(objXMLHTTP.responseText);
}

The first noticeable change from the earlier asynchronous request (refer to Listing 7-2) is that the method has been changed from GET to POST; this is because it is necessary to post the SOAP envelope to the web service. This leads to the second change; the URI in the open method is now the address of the web service instead of a filename.

Perhaps the biggest changes are the addition of two setRequestHeader methods. The first one sets the SOAPAction to the web service's namespace and the method to be invoked. It is important to note that it is absolutely necessary for the SOAPAction header to be identical to the method in the SOAP envelope. If they aren't identical, it won't work. Personally, I spent a lot of time chasing my tail trying to figure out what was wrong whenever the methods were different, but, then, I was raised by wolves and have a strong tendency to chase my tail.

The second setRequestHeader is the easy one; all that it does is set the Content-type to text/xml. As if we'd be doing anything else. But this raises the question of what the response from the web service will look like, beyond being XML.

Well, there are essentially two possible responses; either it worked or it didn't. If it worked, it will look a lot like the response shown in Listing 7-10. However, there could be some differences. For instance, it could be an XML document instead of the "Grrr!", but this is only an example, so why strain ourselves?

Listing 7-10. The Response

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <monsterResponse xmlns="http://tempuri.org/">
      <monsterResult>Grrr!</monsterResult>
    </monsterResponse>
  </soap:Body>
</soap:Envelope>

The second possible response is broken into two parts. The first part is called a SOAP fault. Basically, it means that something is wrong with the request, such as the methods not being identical. Listing 7-11 shows a SOAP fault that was created when I changed the SOAPAction in the request header to xxxx when it should have been monster.

Listing 7-11. A SOAP Fault

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <soap:Body>
   <soap:Fault>
     <faultcode>soap:Client</faultcode>
     <faultstring>
      System.Web.Services.Protocols.SoapException: Server
      did not recognize the value of HTTP Header
      SOAPAction: http://tempuri.org/xxxx.
   at
System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
   at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
   at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type,
HttpContext context, HttpRequest request, HttpResponse response)
   at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type
type, HttpContext context, HttpRequest request, HttpResponse response,
Boolean&amp; abortProcessing)
</faultstring>
      <detail/>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

The final two possible responses also cover errors. For example, there could be errors that are not handled correctly in the web service. This could result in the web service returning text concerning the error instead of either a SOAP response or a SOAP fault. It is important to take this into consideration when creating a web service.

Although the language C# was used here for writing the web services, it is important to remember that these techniques can be applied to a whole slew of languages. In the end, the choice of language is yours, or it belongs to the powers-that-be, or somewhere in the hierarchy.


Previous Page
Next Page




JavaScript Editor Free JavaScript Editor     JavaScript Debugger


©