Overview
ASP.NET AJAX provides a way to instantiate client side types using a declarative programming model ala ASP.NET. One of the simplest examples of declarative code is the following, which displays a message after the page is loaded:
<%@ Page %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Hello XML-script</title>
</head>
<body>
<form id="form1"
runat="server">
<asp:ScriptManager ID="TheScriptManager" runat="server">
<Scripts>
<asp:ScriptReference
Assembly="Microsoft.Web.Preview"
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<script type="text/xml-script">
<page xmlns="http://schemas.microsoft.com/xml-script/2005">
<components>
<application load="page_load" />
</components>
</page>
</script>
<script type="text/javascript">
<!--
function page_load(sender, e)
{
alert("Hello World!");
}
//-->
</script>
</form>
</body>
</html>
Note that in order to use the xml-script feature you must download the Futures CTP package from the Microsoft Ajax website and add a reference to the PreviewScript.js file contained in the Microsoft.Web.Preview assembly.
A block of declarative code is always embedded into a script tag with the type attribute set to text/xml-script. The declarative code in the example isn't difficult to understand; we have a root page element that encapsulates a components element, which is the standard form of a generic xml-script block.
Inside the components element we find an application node with the load attribute set to the name of the function declared in the JavaScript code block. The load attribute is parsed as an event name and its value is parsed as the reference to a function that will be added to the corresponding list of event handlers. Since the application element is mapped to the Sys.Application instance, the result is that page_load() will be called when Sys.Application raises its load event.
How is this possible? The answer is that the declarative code is based on a mapping between xml elements and the methods, properties and events exposed by an ASP.NET AJAX class. This kind of mapping exists for every class that exposes a type descriptor, and every class that exposes a type descriptor can be used in declarative code.
Type descriptors
A type descriptor is an object that describes the properties, methods and events exposed by a class. Every class that intends to provide a descriptor should implement the ITypeDescriptorProvider interface, which defines a single method called getDescriptor(); this method must return the type descriptor associated to the class. The prototype of the ITypeDescriptorProvider interface is declared as follows:
Sys.Preview.ITypeDescriptorProvider.prototype = {
getDescriptor: Sys$Preview$ITypeDescriptorProvider$getDescriptor
}
Another way of exposing a type descriptor (that eliminates the dependency from Sys.Preview) is adding a descriptor expando to the class. If we browse the PreviewScript.js file (that contains part of the classes in the Sys.Preview namespace) we can find many descriptors exposed in this way. For example, the following code shows the descriptor of the Sys.Preview.Button class:
Sys.Preview.UI.Button.descriptor = {
properties: [ { name: 'command', type: String },
{ name: 'argument', type: String } ],
events: [ { name: 'click' } ]
}
A type descriptor is an object (typically represented with a JavaScript dictionary, that is a comma-separated list of attribute and value pairs enclosed in curly braces, as in { name: "value" }) that contains the following attributes:
- properties, holds an array of property descriptors
- events, holds an array of event descriptors
- methods, holds an array of method descriptors
Each array also contains a set of descriptors, but this time their purpose is to describe a particular property, event or method rather than the type. For example, let's examine the descriptor contained in the array of events:
{ name : 'click' }
This descriptor simply tells that the Button class exposes an event named click. The array of properties contains two descriptors:
{ name: 'command', type: String }
{ name: 'argument', type: String }
The first descriptor describes a property called command that is of type String. The second descriptor tells us that the Button class exposes a property of type string, called argument.
Type descriptors enable reflection of client side types and are independent from xml-script. Nonetheless, the xml-script parser uses them extensively to map properties, methods and events to XML elements in declarative code.
By examining a type descriptor, we are able to write the declarative code needed to create an instance of that type, without knowing anything of how xml-script works. Compare the following XML with the type descriptor of the Button class:
<button id="myButton" command="save" click="myButton_click" />
In the above XML, the name of the class (Sys.Preview.UI.Button) is mapped to the name of the element (button), while properties are mapped to attributes; the value of each attribute will be assigned to the corresponding property. The click event is also mapped to an attribute, and its value is the name of a JavaScript function called myButton_click, which is in charge of handling the event.
Where does the id property come from? The Button class inherits from Sys.Component, and the id property is inherited from this class. If you search for the type descriptor of Sys.Component in the PreviewScript.js file, you'll find also the description of the id property:
Sys.Component.descriptor = {
properties: [ {name: 'dataContext', type: Object},
{name: 'id', type: String},
{name: 'isInitialized', type: Boolean, readOnly: true},
{name: 'isUpdating', type: Boolean, readOnly: true} ],
events: [ {name: 'propertyChanged'} ]
}
Describing a method also requires providing the description of its parameters. The following code shows the methods attribute extracted from the type descriptor exposed by the Sys.Preview.Net.ServiceMethodRequest class:
methods: [ {name: 'invoke', params: [ {name: 'userContext', type: Object} ] } ]
In this case, the class is exposing a single method called invoke (as told by the name attribute of the method descriptor). This method accepts a single parameter called userContext, which is of type Object. Parameters are described in the array stored in the params attribute, and each parameter has an associated parameter descriptor.
Conclusions
In this tutorial we've seen a basic example of an ASP.NET page that contains a block of declarative code; then, we introduced type descriptors and learned how to read them. Type descriptors provide reflection for client side types in the Microsoft Ajax Library. They are also used to support the declarative programming model, which allows instantiating client side types by using declarative xml syntax.
In the next tutorial we'll continue to examine the mapping between type descriptors and XML elements.
References
Xml-script tutorial Part 1
Xml-script tutorial Part 2
Xml-script tutorial Part 3
Xml-script tutorial Part 4
About Alessandro Gallo
 |
Alessandro "Garbin" Gallo is a Microsoft MVP in the Visual ASP/ASP.NET category and a .NET developer/consultant. He is a contributor for the Ajax Control Toolkit project, owned by Microsoft. Alessandro won the Grand Prize at the "Mash-it-up with ASP.NET AJAX" contest held by Micr...
View complete profile
|
Top Articles in this category
Introduction to the PopupControl Extender
The PopupControl extender is a way to render a server control popup to the user, so that the user can perform some action (say click on a textbox), the user selects a value in a control that dynamically appears, and that value is posted back to the originating server control.
The UpdatePanel opened: what happens behind the scenes?
The UpdatePanel is one of the coolest features of Microsoft's ASP.NET AJAX. It magically lets you enhance your web sites with AJAX goodness, with very little cost to you as a developer. If you are like me though, you'll be feeling just a little bit uncomfortable simply dragging the UpdatePanel onto your web form, and then letting it do its stuff. We want to understand what it is doing on our behalf.
Xml-script tutorial Part 3
In the first and second part of this tutorial on xml-script we introduced the declarative programming model and illustrated how to handle events raised by the client Microsoft Ajax objects. Events can be handled by invoking a global JavaScript function or by using actions; in this third part we'll talk about the InvokeMethod action, which allows calling a method declaratively.
Xml-script tutorial Part 2
In the first part of this tutorial on xml-script we introduced type descriptors and learned how to read them. In this second part we'll see how to declaratively handle events raised by client side controls.
How to invoke a web service method declaratively with MS AJAX
In the following snippet we'll see how is it possible to invoke a web service method asynchronously and processing the results using only declarative code.
|
|
Please login to rate or to leave a comment.