When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, September 26, 2007

An Extensive Examination of Web Services: Part 11

By Scott Mitchell


An Extensive Examination of Web Services Index
An Extensive Examination of Web Services is a multi-part article series spanning several months. Listed below are the current "parts," along with a very brief synopsis and the date published.
  • Part 1 - Examines the basics of Web services, what Web services are, and the technologies and standards that serve as the underpinnings of Web services. (October 8th, 2003)
  • Part 2 - Examines creating Web services using Visual Studio .NET. Looks underneath the hood of the code created by VS.NET. (October 15th, 2003)
  • Part 3 - Examines creating a client application that consumes a Web service. Discusses the purpose and structure of a WSDL document, along with creating and using proxy classes to consume a Web service. (November 5th, 2003)
  • Part 4 - Examines the utility of Web services and common scenarios where Web services make sense. A business-oriented look at Web services. (November 19th, 2003)
  • Part 5 - Takes an in-depth look at XML serialization, which is the process of converting a data type, such as an integer, array, or custom class, into its XML representation, and back again. Every time a message is passed to or from a Web service, XML serialization transpires. (December 17th, 2003)
  • Part 6 - Looks at sending metadata to a Web method through the use of SOAP headers. Examines defining and accepting a SOAP header on the Web service end, and looks at sending a populated SOAP header from the client. (December 31st, 2003)
  • Part 7 - Examines how the incoming and outgoing messages to a Web service can be programmatically modified via SOAP Extensions. (January 21st, 2004)
  • Part 8 - Learn about the Web Service Enhancements (WSE) and Microsoft's free class library for implementing the WSE standards. (June 30th, 2004)
  • Part 9 - See how to implement UsernameToken authentication using the WSE 2.0 Toolkit. (July 14, 2004)
  • Part 10 - Learn how to send large amounts of data as attachments using DIME and WS-Attachments. (September 8th, 2004)
  • Part 11 - Create (and consume) client-side script-accessible Web Services using Microsoft's ASP.NET AJAX framework. (September 26th, 2007)

Introduction


As the previous ten installments in this article series have shown, the .NET Framework makes creating and consuming Web Services a walk in the park. Creating a Web Service is as easy as marking a class with the WebService attribute; Web Services can be easily consumed because the .NET Framework includes tools to build proxy classes given a Web Service's WSDL file. All of the examples we have seen in previous installments in this article series have consumed Web Services from server-side code. That is, a Web Service is consumed when a postback occurs and server-side code in an ASP.NET page creates an instance of the proxy class and invokes one of its methods.

In 2007 Microsoft released their free ASP.NET AJAX framework, which simplifies building AJAX-enabled ASP.NET applications (see An Introduction to AJAX and Atlas with ASP.NET 2.0 for more information). The ASP.NET AJAX framework is best known for its myriad of AJAX-enabled Web controls, but it also includes functionality to create and consume Web Services through client-side script. Best of all, the workflow for creating script-accessible Web Services is very similar to creating Web Services consumed through server-side .NET code. To mark a Web Service as being consumable from client script, simply add the ScriptService attribute; the service can be consumed through script via an auto-generated JavaScript proxy class.

In this article we'll look at how to use Microsoft's ASP.NET AJAX framework to consume Web Services from script. We will also examine how the low-level communication differs between Web Services consumed from .NET code versus Web Services consumed from JavaScript. Read on to learn more!

- continued -

Getting Started with Microsoft's ASP.NET AJAX Framework


The first step for creating script-accessible Web Services is to ensure that you have Microsoft's ASP.NET AJAX framework at your disposal. The AJAX framework does not support ASP.NET version 1.x; if you are using ASP.NET version 2.0 you'll need to download and install the free framework from http://www.asp.net/ajax/. (Refer to the Get Started with ASP.NET AJAX video for more information.) Future versions of ASP.NET will ship with the AJAX Framework, so there will be no need to download and install it separately.

Once you've installed the ASP.NET AJAX framework, launch Visual Studio. From the File menu choose to create a New Project. The New Project dialog box will include an option to create an ASP.NET AJAX-Enabled Web Application. Choosing this option will create a new Web Application Project that references the AJAX Framework assembly (System.Web.Extensions).

The System.Web.Extensions assembly includes essential AJAX-related Web controls and the classes necessary to create script-accessible Web Services. Additionally, this project types creates a default Web.config file with much additional markup. The markup that is germane to this article is the following:

<configuration>
  <system.web>
    <httpHandlers>
      <remove verb="*" path="*.asmx"/>
      <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

    </httpHandlers>
  </system.web>
</configuration>

These two bolded lines remove the default HTTP Handler for Web Service files (.asmx) and replace it with the ScriptHandlerFactory from the ASP.NET AJAX framework. This handler determines whether or not the request is coming from client-side script. If it is not, it dispatches the request to the default .NET Web Service handler. If the request is coming from client-side script, however, it deserializes the incoming parameters, invokes the method, serializes the response, and sends it back to the client.

An alternate HTTP Handler is needed for Web Service requests eminating from client-side script because a different message format protocol is used. Recall that .NET Web Services, by default, serialize the response and request payloads into SOAP envelopes. When the requests are coming from a client-side script call, however, the messages are serialized using JavaScript Object Notation (JSON). JSON is a text-based, lightweight data exchange format that is often used in AJAX-enabled web applications for a host of reasons. A thorough description of JSON is beyond the scope of this article; for more information, read An Introduction to JavaScript Object Notation (JSON) in JavaScript and .NET.

Creating a Script-Accessible Web Service


Creating a script-accessible Web Service is just like creating a regular, server-side accessible Web Service. Start by adding a Web Service to your Web Application Project. This will create a class with the WebService attribute. As we've seen from earlier installments, you can add methods to the Web Service by creating public methods marked with the WebMethod attribute. At this point we have a Web Service that can be called from .NET code. To make it accessible from client-side script, simply add the ScriptService attribute to the class (just like the WebService attribute).

At the end of this article you'll find a downloadable demo application that includes a Web Service named ~/Services/Calculator.asmx. This Web Service is accessible from both .NET code and from client-script. It offers four methods: Add, Subtract, Multiply, and Divide. Each method takes as input two integer parameters and returns the sum, difference, product, or quotient. The following code shows the class and the Add and Divide methods; the Subtract and Multiply methods have been removed for brevity.

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

using System.Web.Script.Services;



namespace ScriptServices.Services
{
   

[ScriptService]


   [WebService(Namespace = "http://example.com/Calculator")]
   public class Calculator : System.Web.Services.WebService
   {
      

[WebMethod]


      public int Add(int x, int y)
      {
         return x + y;
      }

      ... Subtract and Multiply methods removed for brevity ...

      

[WebMethod]


      public int Divide(int x, int y)
      {
         if (y == 0)
            throw new DivideByZeroException("Parameter y cannot be equal to 0.");

         return x / y;
      }
   }
}

Note the addition of the ScriptService attribute. The attribute class is in the System.Web.Script.Services namespace, which is why I have using System.Web.Script.Services;. Each accessible method is marked with the WebMethod attribute.

That's all there it to creating the script-accessible Web Service! It's just like creating a regular Web Service. The only difference is the inclusion of the ScriptService attribute.

Consuming the Web Service from Client-Side Script


To consume a script-accessible Web Service from client-side script, you'll need to start by adding a ScriptManager control to the page. The ScriptManager control is part of the ASP.NET AJAX framework that enables developers to perform AJAX-related operations, including invoking script-accessible Web Services.

From the ScriptManager control, we need to indicate that we want to be able to invoke the Calculator.asmx Web Service. This is accomplished by adding a ServiceReference element to the control's Services section:

<asp:ScriptManager runat="server" ID="scriptManager">
   <Services>
      <asp:ServiceReference path="~/Services/Calculator.asmx" />
   </Services>
</asp:ScriptManager>

This, in essence, builds a JavaScript proxy class for accessing the Web Service from client-side script. Using the proxy class from JavaScript is a cinch. To demonstrate this, the download at the end of the article includes a web page that has two textboxes to collect numbers and four buttons labelled Add, Subtract, Multiply, and Divide. There's also a textbox at the bottom of the page that displays the sum, difference, product, or quotient.

Clicking any of these buttons runs a particular JavaScript method that grabs the numbers entered into the textboxes and calls the Web Service. Here's the abbreviated code from the client-side Add_OnClick function, which runs when the Add button is clicked:

function Add_OnClick()
{
   // Get the values from the textboxes
   var xValue = document.getElementById("X").value;
   var yValue = document.getElementById("Y").value;

   // Call the Web Service!
   

ScriptServices.Services.Calculator.Add(xValue, yValue, CalculationSuccessCallback);


}

To call the Web Service, simply reference the appropriate Web Service method like so: Namespace.WebServiceName.Method(parameters, SuccessCallbackMethod, FailureCallbackMethod). For this example, the Web Service's namespace is ScriptServices.Services (to verify this, check the namespace value in the code listing in the "Creating a Script-Accessible Web Service" section); the Web Service name is Calculator and the method to call is Add. Two values are passed in as the parameters to Add (xValue and yValue). Web Service calls through script are asynchronous, meaning that control returns to the browser immediately after the above bolded line is executed. When the Web Service returns, the CalculationSuccessCallback function (which we need to create) is invoked:

function CalculationSuccessCallback(serviceResult)
{
   var ResultsTextBox = document.getElementById("Results");
   ResultsTextBox.value = serviceResult;
}

serviceResults contains the actual value returned by the Web Service method (for Add, it's the sum of the two input parameters). This return value is then displayed in the results textbox at the bottom of the page.

Handling Web Service Invocation Errors


If the Web Service call completes as expected, the specified function (CalculationSuccessCallback, in this case) is invoked. But what happens if something goes awry? Perhaps the web server that the Web Service runs on is down. Or maybe the executed Web Service method threw an exception. The Divide method, for example, will bomb out if the user tries to divide by zero. How is such a situation handled in the client script?

If we do not modify our code at all, a failed Web Service invocation fails silently. The CalculationSuccessCallback function is never called. No script error is raised. It's as if the Web Service call was never made. If you want to handle script errors, you need to instruct the proxy class to call a different method in the face of an error. This can be accomplished by specifying the failure callback method much like we did with the successful callback method:

ScriptServices.Services.Calculator.Add(xValue, yValue, CalculationSuccessCallback, CalculationFailedCallback);

We then need to create this CalculationFailedCallback method. The method is passed a WebServiceError object that contains details about the exception.

function CalculationFailedCallback(serviceError)
{
   // Display error message
   alert("ERROR: " + serviceError.get_message());

   var ResultsTextBox = document.getElementById("Results");
   ResultsTextBox.value = "THERE WAS AN ERROR";
}

The above function starts by displaying the exception message in a messagebox. It then displays the text, "THERE WAS AN ERROR" in the results textbox.

Conclusion


Traditionally, Web Services were called from compiled programs like from Windows Applications and the code-behind classes of ASP.NET web pages. But as web applications are continually pushing more functionality down to the client in the name of UI responsiveness, developers are needing to invoke Web Services directly from the client, without the cost of a roundtrip back to the server. Microsoft's ASP.NET AJAX framework makes it easy to create script-accessible Web Services, and also offers integrated tools for invoking said Web Services directly through JavaScript. Rather than use SOAP, these Web Services use JSON, a popular message protocol for AJAX-enabled web applications.

Happy Programming!

  • By Scott Mitchell


    Attachments:


  • Download the Web Service and Client Files Used in this Article



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article