Printer Friendly Version      Send     
Click to Rate and Give Feedback
Related Articles

Matt Milner takes a look at some of the challenges and techniques related to testing Windows Workflow Foundation activities, workflows, and associated components.

Matt Milner

MSDN Magazine November 2008

...

Read more!

To introduce you to VSTO Power Tools Office interop API extensions, we’ll walk through the development of an application that automates Outlook, Excel, and Word.

Andrew Whitechapel, Phillip Hoff, and Vladimir Morozov

MSDN Magazine December 2008

...

Read more!

The heart of Windows Workflow Foundation is its declarative programming model. Here are some best practices to consider when using WF to realize software solutions in the real world.

Josh Lane

MSDN Magazine December 2008

...

Read more!

Choosing the right design pattern for your ASP.NET Web application can help you achieve the separation of concerns between your presentation layer and the layers beneath it.

Dino Esposito

MSDN Magazine December 2008

...

Read more!

This month we take a look at FxCop and other tools that enforce your design rules, along with jQuery.

Scott Mitchell

MSDN Magazine December 2008

...

Read more!

Also by this Author

As I write this column, the release candidates of the Microsoft® .NET Framework 2.0 and Visual Studio® 2005 have just come out, and by the time you read this, they will both already be on the shelves. It feels like it's been a long time coming.

Fritz Onion

MSDN Magazine January 2006

...

Read more!

Fritz Onion demonstrates how the ListView control in ASP.NET 3.5 makes data-binding tasks easier with support for styling with CSS, flexible pagination, and a full complement of sorting, inserting, deleting, and updating features.

Fritz Onion

MSDN Magazine March 2008

...

Read more!

Building a customizable Web site complete with a collection of pluggable Web Parts is fairly easy with the portal infrastructure of ASP. NET 2. 0. This model is very flexible, allowing users to easily place your Web Parts anywhere on the Web page so they are free to customize your site.

Fritz Onion

MSDN Magazine July 2006

...

Read more!

View state is a wonderful thing. It allows the ASP.NET developer to maintain state for server-side controls that are not form elements.Used judiciously, it can improve the user experience. But in the wrong hands, it can cause your pages to grind to a halt. The release of ASP.NET 2.0 will include a variety of improvements to view state that will make it easier to use and less likely to slow performance.

Fritz Onion

MSDN Magazine October 2004

...

Read more!

The Web Service Software Factory is designed to provide guidance and enhanced tools for building Web services using ASMX or WCF.

Fritz Onion

MSDN Magazine August 2007

...

Read more!

Popular Articles

Now you can perform efficient, sophisticated text analysis using regular expressions in SQL Server 2005.

David Banister

MSDN Magazine February 2007

...

Read more!

Jason Clark

MSDN Magazine July 2003

...

Read more!

Jeff Prosise explains when it's better to use UpdatePanel and when it's better to use asynchronous calls to WebMethods or page methods instead.

Jeff Prosise

MSDN Magazine June 2007

...

Read more!

Chris Tavares explains how the ASP.NET MVC Framework's Model View Controller pattern helps you build flexible, easily tested Web applications.

Chris Tavares

MSDN Magazine March 2008

...

Read more!

C# allows developers to embed XML comments into their source files-a useful facility, especially when more than one programmer is working on the same code. The C# parser can expand these XML tags to provide additional information and export them to an external document for further processing. This article shows how to use XML comments and explains the relevant tags. The author demonstrates how to set up your project to export your XML comments into convenient documentation for the benefit of other developers. He also shows how to use comments ...

Read more!

Our Blog

Earlier this year MSDN Magazine embarked on a collaborative project with Behind the Code, an interview program airing on MSDN Channel 9. In this program, Robert Hess interviews prominent developers at Microsoft, and those developers also write a column for { End Bracket } in MSDN Magazine. In the newest interview, Richard Ward talks about working on the core infrastructure components of future versions of Windows, as well as ...

Read more!

Every month, the CLR team gives us insight into the core of managed code, .NET programming best practices, technologies underlying the CLR and .NET Framework, and other tips and suggestions.

In the December 2008 issue of MSDN Magazine, Erika Fuentes and Eric Eilebrecht cover some common issues developers encounter when tuning ...

Read more!

With the releases of LINQ to SQL and the ADO.NET Entity Framework, developers now have two products from Microsoft designed to tie together relational data and object-oriented programming.

In the December 2008 issue of MSDN Magazine, Anthony Sneed provides a roadmap to these technologies and demonstrates how you can create ...

Read more!

C# developers can use the Visual Studio Tools for the Office System (VSTO) Power Tools Office interop API extensions to streamline Office application development. The extensions provide a thin, strongly typed layer over the loosely typed Office object models.

In the December 2008 issue of MSDN Magazine, Andrew Whitechapel, Phillip Hoff, and Vladimir Morozov walk you through developing ...

Read more!

It’s helpful to think about secure design from a more holistic perspective by using threat models to drive your security engineering process.

In the November 2008 issue of MSDN Magazine, Michael Howard proposes using the threat model to help drive other SDL security requirements, primarily code review priority, fuzz testing priority, ...

Read more!

Extreme ASP.NET
Client-Side Web Service Calls with AJAX Extensions
Fritz Onion

Code download available at: ExtremeASPNET2007_01.exe (160 KB)
Browse the Code Online
Since its inception, ASP.NET has fundamentally been a server-side technology. There were certainly places where ASP.NET would generate client-side JavaScript, most notably in the validation controls and more recently with the Web Part infrastructure, but it was rarely more than a simple translation of server-side properties into client-side behavior-you as the developer didn't have to think about interacting with the client until you received the next POST request. Developers needing to build more interactive pages with client-side JavaScript and DHTML were left to do it on their own, with some help from the ASP.NET 2.0 script callbacks feature. This has changed completely in the last year.
At the Microsoft Professional Developer's Conference in September 2005, Microsoft unveiled a new add-on to ASP.NET, code-named "Atlas," which was focused entirely on leveraging client-side JavaScript, DHTML, and the XMLHttpRequest object. The goal was to aid developers in creating more interactive AJAX-enabled Web applications. This framework, which has since been renamed with the official titles of Microsoft® AJAX Library and the ASP.NET 2.0 AJAX Extensions, provides a number of compelling features ranging from client-side data binding to DHTML animations and behaviors to sophisticated interception of client POST backs using an UpdatePanel. Underlying many of these features is the ability to retrieve data from the server asynchronously in a form that is easy to parse and interact with from client-side JavaScript calls. The topic for this month's column is this new and incredibly useful ability to call server-side Web services from client-side JavaScript in an ASP.NET 2.0 AJAX Extensions-enabled page.

Calling Web Services with AJAX
If you have ever consumed a Web service in the Microsoft .NET Framework, either by creating a proxy using the wsel.exe utility or by using the Add Web Reference feature of Visual Studio®, you are accustomed to working with .NET types to call Web services. In fact, invoking a Web service method through a .NET proxy is exactly like calling methods on any other class. The proxy takes care of preparing the XML based on the parameters you pass, and it carefully translates the XML response it receives into the .NET type specified by the proxy method. The ease with which developers can use the .NET Framework to consume Web service endpoints is incredibly enabling, and is one of the pillars that make service-oriented applications feasible today.
The ASP.NET 2.0 AJAX Extensions enable this exact same experience of seamless proxy generation for Web services for client-side JavaScript that will run in the browser. You can author an .asmx file hosted on your server and make calls to methods on that service through a client-side JavaScript class. For example, Figure 1 shows a simple .asmx service that implements a faux stock quote retrieval (with random data).
<%@ WebService Language="C#"
               Class="MsdnMagazine.StockQuoteService" %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
// From Microsoft.Web.Extensions.dll assembly
using Microsoft.Web.Script.Services; 

namespace MsdnMagazine
{
    [WebService(Namespace = "http://msdnmagazine.com/ws")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ScriptService]
    public class StockQuoteService : WebService
    {
        static Random _rand = new Random(Environment.TickCount);

        [WebMethod]
        public int GetStockQuote(string symbol)
        {
            return _rand.Next(0, 120);
        }
    }
}

In addition to the standard .asmx Web service attributes, this service is adorned with the ScriptService attribute that makes it available to JavaScript clients as well. If this .asmx file is deployed in an ASP.NET AJAX-Enabled Web application, you can invoke methods of the service from JavaScript by adding a ServiceReference to the ScriptManager control in your .aspx file (this control is added automatically to your default.aspx page when you create a Web site in Visual Studio using the ASP.NET AJAX-enabled Web site template):
<asp:ScriptManager ID="_scriptManager" runat="server">
  <Services>
    <asp:ServiceReference Path="StockQuoteService.asmx" />
  </Services>
</asp:ScriptManager>
Now from any client-side JavaScript routine, you can use the MsdnMagazine.StockQuoteService class to call any methods on the service. Because the underlying mechanism for invocation is intrinsically asynchronous, there are no synchronous methods available. Instead, each proxy method takes one extra parameter (beyond the standard input parameters)- a reference to another client-side JavaScript function that will be called asynchronously when the method completes. The example page shown in Figure 2 uses client-side JavaScript to print the result of calling the stock quote Web service to a label (span) on the page.
<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html  >
<head runat="server">
 <title>ASP.NET AJAX Web Services: Web Service Sample Page</title>

 <script type="text/javascript"> 
    function OnLookup()
    {           
      var stb = document.getElementById("_symbolTextBox");  
      MsdnMagazine.StockQuoteService.GetStockQuote(
        stb.value, OnLookupComplete);
    }
    
    function OnLookupComplete(result)
    {
      var res = document.getElementById("_resultLabel");
      res.innerHTML = "<b>" + result + "</b>";
    }
  </script>    
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="_scriptManager" runat="server">
      <Services>
        <asp:ServiceReference 
             Path="services/StockQuoteService.asmx" />
      </Services>
    </asp:ScriptManager>
    <div>
    <h1>ASP.NET AJAX Web Services: Web Service Sample Page</h1>
    Enter symbol: 
    <asp:TextBox runat="server" id="_symbolTextBox" />
    <br />
    <input onclick="OnLookup();" id="_lookupButton" type="button" 
           value="Lookup" />
    <br />
    <asp:Label runat="server" id="_resultLabel" />
    </div>
    </form>
</body>
</html>

If something goes wrong with a client-side Web service call, you definitely want to let the client know, so it's usually wise to pass in another method that can be invoked if an error, abort, or timeout occurs. For example, you might change the OnLookup method shown previously as follows, and add an additional OnError method to display any problems:
function OnLookup()
{           
  var stb = document.getElementById("_symbolTextBox");  
  MsdnMagazine.StockQuoteService.GetStockQuote(
    stb.value, OnLookupComplete, OnError);
}
    
function OnError(result)
{
  alert("Error: " + result.get_message());
}
This way if the Web service call fails, you will notify the client with an alert box. You can also include a userContext parameter with any Web service calls made from the client, which is an arbitrary string passed in as the last parameter to the Web method, and it will be propagated to both the success and failure methods as an additional parameter. In this case, it might make sense to pass the actual symbol of the stock requested as the userContext so you can display it in the OnLookupComplete method:
function OnLookup()
{           
  var stb = document.getElementById("_symbolTextBox");  
  MsdnMagazine.StockQuoteService.GetStockQuote(
    stb.value, OnLookupComplete, OnError, stb.value);
}

function OnLookupComplete(result, userContext)
{
  // userContext contains symbol passed into method
  var res = document.getElementById("_resultLabel");
  res.innerHTML = userContext + " : <b>" + result + "</b>";
}
If you find that you're making many different calls to a Web service, and that you re-use the same error and/or complete methods for each call, you can also set the default error and succeeded callback method globally. This avoids having to specify the pair of callback methods each time you make a call (although you can choose to override the globally defined methods on a per-method basis). Here is a sample of the OnLookup method that sets the default succeeded and failed callback methods globally instead of on a per-call basis.
// Set default callbacks for stock quote service
MsdnMagazine.StockQuoteService.set_defaultSucceededCallback(
                 OnLookupComplete);
MsdnMagazine.StockQuoteService.set_defaultFailedCallback(
                 OnError);
function OnLookup()
{           
  MsdnMagazine.StockQuoteService.GetStockQuote(stb.value);
}
Another interesting alternative to building a complete .asmx file for your Web service methods is to embed the Web service methods directly in the page class. If it doesn't make sense to build a complete Web service endpoint for the methods you want to call, you can expose a Web method from your page that is callable from client-side JavaScript by adding a server-side method to your page (either directly in the page or in the codebehind) and annotating it with the WebMethod attribute. You will then be able to invoke it via the client-side object PageMethods. The example in Figure 3 shows the stock quote service sample rewritten to be entirely contained in a single page instead of split into a separate Web service.
<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html  >
<head runat="server">
<title>ASP.NET AJAX Web Services: Web Service Sample Page</title>
  <script runat="server">
        private static Random _rand = new Random();
        
        [WebMethod]
        public static float GetStockQuoteFromPage(string symbol)
        {
            return _rand.Next(0, 120);
        }
  </script>

  <script type="text/javascript">    
  function OnLookup()
  {           
    var stb = document.getElementById("_symbolTextBox");       
    PageMethods.GetStockQuoteFromPage(stb.value,
                  OnLookupComplete);
  }
    
  function OnLookupComplete(result)
  {
    var res = document.getElementById("_resultLabel");
    res.innerHTML = "<b>" + result + "</b>";
  }
  </script>  
</head>
<body>
    <form id="form1" runat="server">
    <div>    
    <h1> ASP.NET AJAX Web Services: Web Service Sample Page </h1>
     Enter symbol: 
        <asp:TextBox runat="server" id="_symbolTextBox" />
        <br />
        <input onclick="OnLookup();" id="_lookupButton" 
               type="button" value="Lookup" />
        <br />
        <asp:Label runat="server" id="_resultLabel" />
    </div>
    </form>
</body>
</html>

Bear in mind that these client-side proxies can only be generated from ASP.NET .asmx endpoints, Windows Communication Foundation .svc endpoints, or WebMethods embedded directly in a page, and are not a general mechanism for calling arbitrary Web services. In fact, there is a general restriction on the underlying XmlHTTPRequest object that requests be restricted to the same domain from which the page was loaded (for security reasons), so this technique could not be used to call arbitrary Web services regardless of whether the client-side proxies supported it. If you do find the need to call external Web services, your best bet is to set up a bridge .asmx endpoint in your own application that calls into a .NET proxy class (generated with wsdl.exe or Add Web Reference in Visual Studio) for the external Web service.

How It Works
It might seem surprising at first that you can take a standard .asmx Web service and access it from client-side JavaScript within a browser with almost no changes. The secret lies in the registration of a new .asmx HTTP handler, added to the configuration file of every ASP.NET AJAX-enabled Web site:
<httpHandlers>
  <remove verb="*" path="*.asmx"/>
  <add verb="*" path="*.asmx" 
       type="Microsoft.Web.Services.ScriptHandlerFactory" 
       validate="false"/>
</httpHandlers>
This newly registered handler will invoke the standard Web service handler (System.Web.Services.Protocols.WebServiceHandlerFactory) if it is a standard Web service request made to an .asmx endpoint. If, however, the request has a trailing /js in the URL or contains a query string with an mn= variable (such as ?mn=GetStockQuote), the handler will either return a chunk of JavaScript that creates a client-side proxy for the Web service (the /js option), or it will invoke the corresponding method defined in the WebService-derived class and package up the response in a JavaScript Object Notation (JSON)-encoded string (the ?mn= option).
When a page includes a client-side reference to an .asmx service (via the ServiceReference element within the ScriptManager control), it injects a script element that references the .asmx file with a trailing /js, creating a proxy in the client. For example, the stock quote page I built earlier rendered with the following script element in it:
<script src="StockQuoteService.asmx/js" 
        type="text/javascript"></script>
This is, of course, in addition to the script references added for the Microsoft AJAX Libraries, which include the client-side features needed to interact with this proxy. If you try navigating to this endpoint yourself, you will see the following JavaScript (elided):
Type.registerNamespace('MsdnMagazine');
MsdnMagazine.StockQuoteService=function() {
  this._timeout = 0;
  this._userContext = null;
  this._succeeded = null;
  this._failed = null;
}
MsdnMagazine.StockQuoteService.prototype={
GetStockQuote:Sys.Net._WebMethod._createProxyMethod(this,
     "GetStockQuote", 
     "MsdnMagazine.StockQuoteService.GetStockQuote",
     "symbol"), ...
}
This JavaScript is using features of the Microsoft AJAX Libraries (like namespaces and the WebMethod class) that are included with every page that includes a ScriptManager control. The proxy method created by this JavaScript is initialized to invoke the .asmx endpoint with the query string ?mn=GetStockQuote in this case, so that whenever you call MsdnMagazine.StockQuoteService.GetStockQuote from the client, it turns into an asynchronous Web request for the same .asmx endpoint. This combination of client-side proxy generation and server-side support for JavaScript-initiated Web service calls means you can include client-side calls to your .asmx Web services in an intuitive way.

Serialization
The default serialization of AJAX-based Web services is JSON. If you look at a trace of the page shown in the last section in action, the bodies of the Web service request and response look like this:
Request: {"symbol":"ABC"}
Response: 51
This is definitely not the standard XML format you are probably accustomed to seeing when calling your .asmx Web services. Since .asmx endpoints were built to serialize into XML, one of the major additions of the ASP.NET 2.0 AJAX Extensions is a JSON serializer. There are actually two of them-one implemented in JavaScript for use on the client, and one implemented in .NET for use on the server, specifically when an AJAX client invokes an .asmx endpoint. The server-side serializer is available through the Microsoft.Web.Script.Serialization.JavaScriptSerializer class and the client-side serializer is available through Sys.Serialization.JavaScriptSerializer. One of the major advantages of using JSON as a serialization format over XML is that you can deserialize objects in JavaScript by simply evaluating a JSON string. The deserialize method of the client serializer class ends up being very short (error checking removed):
Sys.Serialization.JavaScriptSerializer.deserialize=
    function(){eval('('+data+')');}
The serialize method of the JavaScriptSerializer, on the other hand, is considerably more involved. Another advantage to using JSON is its relatively compact representation compared with the XML equivalent.
Much as the XmlSerializer used by standard Web services serializes types to XML, you can take almost any .NET type and serialize it into JSON with JavaScriptSerializer. If you want to try it yourself, it's just a matter of calling the Serialize method of the JavaScriptSerializer class. Figure 4 shows a sample console application that serializes the complex Person type (shown in Figure 5), as an example. (It must include an assembly reference to the Microsoft.Web.Extensions.dll installed in the Global Assembly Cache (GAC) with the ASP.NET AJAX Extensions.)
namespace MsdnMagazine.SampleTypes
{
    public class Person
    {
        private string _firstName;
        private string _lastName;
        private int _age;
        private bool _married;

        public bool Married
        {
            get { return _married; } set { _married = value; }
        }

        public int Age
        {
            get { return _age; } set { _age = value; }
        }

        public string FirstName
        {
            get { return _firstName; } set { _firstName = value; }
        }

        public string LastName
        {
            get { return _lastName; } set { _lastName = value; }
        }
    }
}

using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Web.Script.Serialization;

class App
{
    static void Main()
    {
        Person p = new Person();
        p.FirstName = "Bob";
        p.LastName = "Smith";
        p.Age = 33;
        p.Married = true;

        JavaScriptSerializer jss = new JavaScriptSerializer();
        string serializedPerson = jss.Serialize(p);
        Console.WriteLine(serializedPerson);
    }
}

The output of the console application would be the Person class in JSON format, or:
{"Married":true,"Age":33,"FirstName":"Bob","LastName":"Smith"}
Like XmlSerializer, JavaScriptSerializer will only serialize publicly accessible data in a type, and there is no support for resolving cyclic references. But any types that can be serialized by a standard .asmx Web service will work fine with this serializer (and yes, this includes DataSet). With this knowledge in place, you can build a more complex Web service, knowing that it will handle complex types as easily as any SOAP-based Web service defined in an .asmx file.
The example in Figure 6 shows a Web service called MarriageService that implements a Marry method to take two Person objects (as defined earlier) and modify their attributes appropriately. (The accompanying ASP.NET page is included with the code download for this issue.)
<%@ WebService Language="C#" 
    Class="MsdnMagazine.MarriageService" %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using Microsoft.Web.Script.Services;
using MsdnMagazine.SampleTypes;

namespace MsdnMagazine
{
    [WebService(Namespace = "http://msdnmagazine.com/ws")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ScriptService]
    [GenerateScriptType(typeof(Person))]
    public class MarriageService : WebService
    {
        [WebMethod]
        public Person[] Marry(Person[] couple)
        {
          if (couple.Length != 2)
            throw new ArgumentException("2 persons only!");
          if (couple[0].Married || couple[1].Married)
            throw new ArgumentException("Tell your spouse first!");
            
          couple[0].LastName += "-" + couple[1].LastName;
          couple[1].LastName = couple[0].LastName;
          couple[0].Married = couple[1].Married = true;
          return couple;
        }
    }
}

If you'd rather work with XML in your client-side script, that option is available as well. In addition to the standard WebMethod attribute used when defining Web services, there is a new attribute in the Microsoft.Web.Script.Services namespace called ScriptMethod, which has a ResponseFormat property that can be set to either Json or Xml (it defaults to Json).
namespace PS
{
    [ScriptService] 
    [WebService(Namespace = "http://pluralsight.com/ws")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class StockQuoteService : WebService
    {
        [WebMethod]
        public int GetStockQuote(string symbol)
        {
            return (new Random()).Next(0, 120);
        }
    }
}
The serialized response would then be:
<?xml version="1.0" encoding="utf-8"?><int>74</int>
It is up to you when you invoke this method from client-side JavaScript to handle the XML response. If you plan on running a transformation on it or are already using MSXML, this may be useful.

Conclusion
It's worth pointing out that the ASP.NET 2.0 AJAX Extensions provide two pre-built services to tap into specific ASP.NET 2.0 application services from client-side code: ProfileService and AuthenicationService. With these two client-side proxy classes you can set and retrieve profile values for individual clients, as well as perform authentication (via the default Membership provider) and grant authentication cookies completely within client script.
While many discussions and demonstrations of the ASP.NET 2.0 AJAX Extensions focus on the flashy controls that enable responsive user interfaces, one of the most impressive and useful features is the ability to call Web services directly from client-side JavaScript. With a full .NET Framework/JSON serializer, direct integration with the familiar .asmx Web services, support for batching, and auto-generated bridges to external Web services, the breadth and depth of support for Web services makes this perhaps the most compelling feature of all.

Send your questions and comments for Fritz to  xtrmasp@microsoft.com..


Fritz Onion is a cofounder of Pluralsight, a Microsoft .NET training provider, where he heads the Web development curriculum. Fritz is the author of Essential ASP.NET (Addison Wesley, 2003) and Essential ASP.NET 2.0 (Addison Wesley, 2006). Reach him at pluralsight.com/fritz.

Page view tracker