Web pages were originally built around the document concept, with people viewing documents located on remote servers using web browsers. The first big shift from that paradigm happened when programmers started using server-side code to generate dynamic web pages for their users. That’s how web applications were born.
Web sites are no longer just collections of static documents; they can now accept user input and react to it in different ways. Until recently, most of the innovations in that area were made on the server side. Clients had poor scripting support, and the lack of standards made creating portable code difficult.
We are now facing another revolution, this time on the client side. Most popular browsers already support the XMLHttpRequest
object, which allows the client to call the server from a script to update a page without reloading it. This drastically cuts application response time, so developers can now author web applications whose responsiveness rivals that of some desktop applications. Unfortunately, however, building such applications is still a challenge, because developers still need to write a lot of cross-browser JavaScript code (a difficult task).
Microsoft’s answer to the difficulties in client-side programming is the ASP.NET “Atlas” framework, which we’ll refer to simply as Atlas. This framework provides a lot of features that help developers concentrate on the application logic and let them forget about most browser quirks.
At its lowest level, Atlas implements a browser-compatibility layer that tries to unify the document object model (DOM) under different browsers. Atlas also makes it possible to use several OO-like constructs such as classes, interfaces, namespaces, properties, and delegates with JavaScript in ways that will be familiar to .NET developers. An entire client-side component model has been created to allow objects to interact in a well-defined and predictable manner. Now JavaScript experts can develop script components that non-experts can create declaratively with an XML-based syntax, greatly reducing the amount of script to be written.
Tool | Microsoft ASP.NET Atlas |
Version covered | April 2006 CTP |
Home page | |
Power Tools page | |
Summary | A client- and server-side framework providing components and infrastructure that allow the creation of highly interactive web applications while hiding the complexities of Ajax and JavaScript portability |
License type | Commercial, zero-cost |
Online resources | Documentation, forums, and weblogs (see the home page for links) |
Related tools in this book | Anthem.NET, Ajax.NET Professional |
You can download Atlas from its home page via the prominent Download icon on the site’s header.
The server-side part of Atlas requires ASP.NET 2.0 or later to run. The client-side code supports Microsoft Internet Explorer (IE), Gecko-based browsers such as Mozilla Firefox, and Safari. Opera support is planned for a future release.
The installation comes in a Windows Installer .msi package. It reconfigures Internet Information Services (IIS) and adds new project templates to Visual Studio .NET 2005. Running an Atlas-powered web site requires a local or Global Assembly Cache (GAC) reference to the Microsoft.Web.Atlas.dll assembly.
The Atlas framework comes loaded with features for improving the experience of your users. Three of the most important features simplify the coding of asynchronous partial page updates, provide a means to work with local and third-party web services, and enhance the power of JavaScript as a client scripting language.
Traditional ASP.NET development involves working with controls that generate web page output. Those controls render HTML and send it to the client. The client browser might react to user input and post data back to the server, in which case the server re-creates the page controls, renders the content anew, and sends it back to the client once again. This is not very efficient, especially if a big portion of the page—a navigation pane, for example—stays the same all the time. With Atlas, you can update only portions of the page and send only the changed HTML over the network.
Here’s an example page that accepts a search query in a text box and displays the search results in an unordered list, generated by a data-bound Repeater
control:
<asp:TextBox ID="searchBox" runat="server"></asp:TextBox> <asp:Button ID="searchButton" Text="Search" runat="server" OnClick="searchButton_Click" /> <br /> <asp:Repeater ID="searchResults" runat="server"> <HeaderTemplate> <ul> </HeaderTemplate> <ItemTemplate> <li> <%# Container.DataItem %> </li> </ItemTemplate> <FooterTemplate> </ul> </FooterTemplate> </asp:Repeater>
Every time the user clicks the Search button, the page regenerates all the HTML and sends it back over the network. You can optimize that behavior by placing your controls inside an Atlas UpdatePanel
control, which prevents full-page postbacks caused by any control inside it. In addition, it sends the user input to the server with an Ajax request, limiting server responses to the UpdatePanel
’s contents only.
A single instance of the ScriptManager
control is required on all Atlas-enabled pages. This control is responsible for including various client script resources on the page. To inform all the UpdatePanel
controls on a page that they must do partial instead of full rendering, set the ScriptManager
’s EnablePartialRendering
property to true
, as shown in the following snippet:
<atlas:ScriptManager ID="scriptManager1" runat="server" EnablePartialRendering="true"> </atlas:ScriptManager> <atlas:UpdatePanel ID="searchPanel" runat="server"> <ContentTemplate> <asp:TextBox ID="searchBox" runat="server"></asp:TextBox> <asp:Button ID="searchButton" Text="Search" runat="server" OnClick="searchButton_Click" /> <br /> <asp:Repeater ID="searchResults" runat="server"> <HeaderTemplate> <ul> </HeaderTemplate> <ItemTemplate> <li> <%# Container.DataItem %> </li> </ItemTemplate> <FooterTemplate> </ul> </FooterTemplate> </asp:Repeater> </ContentTemplate> </atlas:UpdatePanel>
The search application will now work without postbacks and update the search panel only, using Ajax requests. However, there’s another problem. Some searches might take a long time, and, particularly to users with slower network connections, it might look as though the application has locked up while waiting for the request to complete. To notify users that the application is awaiting a response from the server, you can include one or more UpdateProgress
controls on the page:
<atlas:UpdateProgress runat="server"> <ProgressTemplate> Loading... </ProgressTemplate> </atlas:UpdateProgress>
An UpdateProgress
control is a template control that displays its contents during a request to the server. Most often, such controls contain an animated GIF image that looks like a progress gauge. The progress area content can be positioned at a custom location via CSS styling.
Update panels can be a great way to reduce network traffic. But by default, an update caused by one panel will update all the panels on the page. You can further optimize this behavior by switching a panel’s Mode
property to Conditional
and configuring some update triggers for the panel. A conditionally updated panel will render and update itself if and only if one of its triggers fires.
For example, consider a page that displays user profile information—say, the user’s name and the last date she logged onto the system—in an update panel. The web page might have a profilePanel
control containing a Refresh button that fetches changed information from the server. A commentsPanel
control might display additional information about the user. Figure 1-1 shows a sample page containing these controls.
We don’t want the second panel to be updated when the user refreshes the first panel. The only time we need to update the second panel is when the user clicks a checkbox that toggles the display of additional information. The checkbox has its AutoPostBack
feature enabled; our CheckedChanged
event handler toggles the visibility of a label control inside the commentsPanel
. We set its Mode
property to Conditional
and add a trigger from the Visual Studio designer by editing the Triggers
property from the property grid, as shown in Figure 1-2.
The trigger will fire when showCommentsCheckBox
raises its CheckedChanged
event. The final version of our page looks like this:
<atlas:ScriptManager ID="scriptManager1" runat="server" EnablePartialRendering="true"> </atlas:ScriptManager> <asp:CheckBox ID="showCommentsCheckBox" runat="server" Text="Show additional comments" AutoPostBack="True" OnCheckedChanged="showCommentsCheckBox_CheckedChanged" /> <atlas:UpdatePanel ID="profilePanel" runat="server" Mode="Always"> <ContentTemplate> Name: <asp:Label ID="nameLabel" runat="server"></asp:Label> <br /> Last Login: <asp:Label ID="loginDateLabel" runat="server"></asp:Label> <br /> <asp:Button ID="refreshButton" Text="Refresh" runat="server" OnClick="refreshButton_Click" /> <br /> </ContentTemplate> </atlas:UpdatePanel> <atlas:UpdatePanel ID="commentsPanel" runat="server" Mode="Conditional"> <ContentTemplate> <asp:Label ID="commentsLabel" runat="server" Visible="false" Text="Some additional info for this user"> </asp:Label> </ContentTemplate> <Triggers> <atlas:ControlEventTrigger ControlID="showCommentsCheckBox" EventName="CheckedChanged" /> </Triggers> </atlas:UpdatePanel>
Updating portions of the page with UpdatePanel
controls is a great way to turn a postback-based site into a full-blown Ajax application. But sometimes, that’s not enough.
Rendering update panels executes the full page lifecycle, so in effect partial rendering reduces only the amount of rendered HTML. All server-side page events (e.g., Init
, Load
, and PreRender
) are still fired, and that overhead can be prohibitive in some situations. In addition, sometimes the raw data—say, an array of number values—is needed on the client side. Rendering that array as HTML and parsing it back with script code is suboptimal and error-prone.
Atlas solves this problem by allowing developers to call web-service methods from JavaScript and get just the data in a very efficient way. All parameters and return values are automatically serialized to the very compact JavaScript Object Notation (JSON) format.
Tip
Atlas achieves this enhanced functionality with web services by including a new HTTP handler for .asmx files. An HTTP handler is an ASP.NET object that handles all of the requests for a certain file type (in this case, any web services setup using the .asmx extension). The custom HTTP handler can then manage the serialization and deserialization of the parameters and return values on their way into and out of the requested web service.
Atlas’s enhanced web-service functionality is one of its major strengths, and it’s something not found in the other Ajax implementations covered in this book.
Suppose we have a web service that returns the air temperature in a given city. Here is a dummy implementation of our web method:
[WebService(Namespace = "http://windevpowertools.com/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class Weather : System.Web.Services.WebService { public Weather( ) { } [WebMethod] public int GetTemperature(string city) { return 30; } }
To call the web method from JavaScript, we need to add a ServiceReference
element to our ScriptManager
control. It includes a script that generates proxy objects, which we can then use to call the service. The actual call is done in a button’s onclick
event handler. The code looks like this:
<atlas:ScriptManager ID="scriptManager1" runat="server" EnablePartialRendering="true"> <Services> <atlas:ServiceReference Path="Weather.asmx" /> </Services> </atlas:ScriptManager> <input type="text" id="cityBox" value="" /> <input type="button" value="Fetch temperature" onclick="FetchTemperature( )" /> <script type="text/javascript"> function FetchTemperature( ) { var city = $('cityBox').value; Weather.GetTemperature(city, WeatherRequestComplete); } function WeatherRequestComplete(result) { alert(result); } </script>
The $( )
function (shown in the statement var city = $(''cityBox'')
.value;
) is Atlas shorthand for document.getElementById( )
, the official W3C API for locating elements in a document. In this example, we get the name of the city that the user has typed in the cityBox
text box. Atlas has taken care to create proxies with the same names as our server objects on the client. GetTemperature( )
is our web method, and Weather
is the name of the server-side class. Note that we pass an additional parameter to our GetTemperature( )
proxy method. The service request is asynchronous, and the result is not immediately available, so we have to provide a callback function that will be called when the request completes. We can also pass two other callback functions: the server-error and request-timeout handlers.
Tip
The example script shows the Weather.asmx service as part of the current web application because JavaScript allows access only to resources in the browser’s home domain. However, the latest Community Technology Preview (CTP) of Atlas includes a new bridging technology that allows applications to create gateways to external web services, thereby breaking this limitation of traditional Ajax. See the Atlas documentation for more information.
What if we have a web service that accepts user-defined objects as parameters? Atlas will generate JavaScript stub classes and will serialize the data when sending it to and from the server.
Here is a dummy implementation of a mapping service that returns a list of nearby restaurants. Our method takes a MapPoint
object as a location parameter and returns a generic list of Restaurant
objects:
[WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class MapWebService : System.Web.Services.WebService { public MapWebService( ) { } [WebMethod] public List<Restaurant> GetRestaurants(MapPoint location) { List<Restaurant> result = new List<Restaurant>( ); Restaurant restaurant = new Restaurant( ); restaurant.Name = "John's Diner"; result.Add(restaurant); restaurant = new Restaurant( ); restaurant.Name = "Giovanni's Trattoria"; result.Add(restaurant); return result; } }
Calling the method from JavaScript is very similar to the way you would call it from C#:
<script type="text/javascript"> function FindNearByRestaurants(x, y) { var point = new MapPoint( ); point.X = x; point.Y = y; MapWebService.GetRestaurants(point, GetRestaurantsComplete); } function GetRestaurantsComplete(result) { for (var i = 0; i < result.length; i++) { var restaurant = result[i]; alert(restaurant.Name); } } </script>
Atlas has generated the client-side MapPoint
and Restaurant
classes and knows how to serialize their properties during the request. The generic list has been turned into a JavaScript array through which we can iterate.
Automatic object serialization saves us a lot of work here, but it may not be available for complex object types. In these cases, developers can extend Atlas with converter classes.
Atlas isn’t just about Ajax functionality. It also tries to simplify client-side development by providing a set of JavaScript-based services. It extends the language and provides ways to define classes, interfaces, namespaces, properties, and delegates. Developers can create self-describing client-side components using the type descriptors infrastructure, components can define properties that can raise change notifications and participate in data binding, and users can define property bindings that allow them to update a component as a result of another component change without a single line of code.
Components can serve many purposes, but the most common component types are controls and behaviors. Controls are presentation objects that usually wrap document elements and provide user interface building blocks. Behavior objects offer a way to separate actions from presentation logic. They typically extend controls by subscribing to their events and performing some actions.
As an example, we’ll create a Sys.UI.Button
control that wraps the saveButton1 input
element. We’ll attach a ConfirmButtonBehavior
component to the control and initialize it with a ConfirmMessage
property of “Are you sure?” From now on, clicking the button will present the user with a confirmation box with the same text. Clicking Cancel will cancel the action and prevent any data submission to the server. Here’s the code:
<input type="submit" value="Save" id="saveButton1" /> <script type="text/javascript"> function pageLoad( ) { var button = new Sys.UI.Button($("saveButton1")); var confirmBehavior = new AtlasControlToolkit.ConfirmButtonBehavior( ); confirmBehavior.set_ConfirmText("Are you sure?"); button.get_behaviors( ).add(confirmBehavior); confirmBehavior.initialize( ); } </script>
Note the Atlas convention of prefixing methods with get_
and set_
. This is how properties are implemented, because JavaScript does not natively support properties. “Setting the ConfirmMessage
property” actually refers to calling the set_ConfirmText( )
method.
The previous example might look like overkill—all we want is to attach a behavior to our button. In fact, wiring behaviors by hand is required in only the most complex scenarios. Atlas provides another way to create and configure components: they can be defined declaratively with an Atlas script. Atlas scripts are blocks of XML (<script type="text/xml-script">
) that contain the component declarations. The syntax of such blocks is very similar to that of ASP.NET control declarations. Using this approach, we can create another button control and attach a ConfirmButtonBehavior
to it:
<input type="submit" value="Save2" id="saveButton2" /> <script type="text/xml-script"> <page xmlns:script="http://schemas.microsoft.com/xml-script/2005" xmlns:atlascontroltoolkit="atlascontroltoolkit"> <components> <button id="saveButton2"> <behaviors> <atlascontroltoolkit:confirmButtonBehavior ConfirmText="Are you sure?" /> </behaviors> </button> </components> </page> </script>
Even the declarative XML script can be daunting to beginners, but fortunately there’s a third option: Atlas web controls. These are ASP.NET server controls that render XML script to the client. Controls that define behaviors for other controls in this way are usually called control extenders. Here is an example of the ConfirmButtonExtender
control that extends a standard ASP.NET button:
<asp:Button ID="serverSaveButton" runat="server" Text="Server Save Button" /> <atlascontroltoolkit:ConfirmButtonExtender ID="confirmButtonExtender1" runat="server"> <atlascontroltoolkit:ConfirmButtonProperties TargetControlID="serverSaveButton" ConfirmText="Are you sure?" /> </atlascontroltoolkit:ConfirmButtonExtender>
The ConfirmButtonExtender
control is a part of the Atlas Control Toolkit, a set of free Atlas controls that are developed and released separately from the main Atlas distribution. The toolkit contains numerous controls that simplify and automate repetitive UI and data-related tasks. You can download the toolkit installer from the Atlas download page.
Get Windows Developer Power Tools now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.