ASP.NET AJAX Development Approach Part 2
Contents |
· 1 Introduction · 2 Type Reflection · 3 Working With Arrays · 4 Working with Primitives · 5 Working With Errors · 6 Global Methods · 7 Remote Calls to the Server · 8 Conclusion |
If you haven’t read Part 1 of this series, I highly recommend reading that article first, as the concepts from that article are applied into looking at the extensions to the existing object of the ASP.NET AJAX architecture. In the first article, I only touched upon the client architectural concepts. In this article, I’ll look at some of the extensions made available in the ASP.NET AJAX that are also useful for custom development.
ASP.NET AJAX framework Series
· Part 1 Overview of the client portion of the ASP.NET AJAX framework.
· Part 2 Overview of the client portion of the ASP.NET AJAX framework.
· Part 3 Overview of the client portion of the ASP.NET AJAX framework.
· Part 4 Overview of the server portion of the ASP.NET AJAX framework.
· Part 5 Overview of rendering the UI of a control with ASP.NET AJAX.
As with the .NET framework’s reflection capabilities, JavaScript also has type reflective capabilities. The Object class has two static methods called getType
and getTypeName
. These methods get information about the type:
Listing 1: Accessing the type in JavaScript
1.var
x = new
Nucleo.Menus.MenuItem(“Test”);
2.var
menuType = Object.getType(x);
3.var
menuTypeName = Object.getTypeName(menuType);
Using the type, it’s possible to determine whether an object is a class, interface, namespace, etc. For instance, the following code determines whether the object is a class.
Listing 2: Determining if a type is a class
1.var
x = new
Nucleo.Menus.MenuItem(“Test”);
2.var
menuType = Object.getType(x);
3.
alert(Type.isClass(menuType));
Because the ASP.NET AJAX framework allows for inheritance and interfaces, the type class has additional support for determining what an object inherits or implements.
Listing 3: Interface implementation
1.var
x = new
Nucleo.Menus.MenuItem(“Test”);
2.
alert(Nucleo.Menus.MenuItem.inheritsFrom(Sys.Component));
3.var
menuType = Object.getType(x);
4.
alert(menuType.implementsInterface(Sys.INotifyPropertyChanged);
So how does the ASP.NET AJAX framework know about all of the type information? Every time an object is registered, the registration process adds it to its internal collection of objects. The descriptor exposes the members of the registered classes, interfaces, etc. Therefore, the Type class has built-in capability to reflect upon an object’s given type definition.
In creating a descriptor for the object created in the previous article’s examples (left out from the previous article), the descriptor would look like the code in Figure 4. The descriptor is not defined in the prototype definition, but is its own script block. Define the descriptor before the registration of the class.
Listing 4: The descriptor attribute
01.
Nucleo.Menus.MenuItem.descriptor = {
02.
properties:
03.
[
04.
{name:caption, type:String},
05.
{name:text, type:String},
06.
{name:visible, type:Boolean}
07.
],
08.
methods:
09.
[
10.
{name: toggleVisiblity}
11.
]
12.
events:
13.
[
14.
{name:visibilityToggled}
15.
]
16.
}
This descriptor defines the members of the MenuItem class, using a collection of dictionaries. Each dictionary specifies a separate member type (property, method, etc.), which also contains a collection of key/value pairs that specify the details of the class. The descriptor contains important information about each of these members. For instance, with properties, the descriptor states whether properties can be null (through the mayBeNull
attribute) or if they are read-only (through the readonly
attribute), and the property’s type information. These attributes help further restrict the type of input allowed.
In its simplest form, an array is represented by the []
notation. This signifies an array, but that doesn’t mean arrays are easy to work with. Some of the extensions to ASP.NET AJAX make working with arrays easy. Below are a few examples of working with arrays:
Listing 5: Working with arrays
01.var
arrayData = [];
02.
Array.add(arrayData, “Honda”);
03.
Array.add(arrayData, “Toyota”);
04.
Array.add(arrayData, “Subaru”);
05.
alert(Array.contains(arrayData, “Honda”));
06.var
index = Array.indexOf(“Toyota”);
07.
Array.insert(arrayData, index, “Lexus”);
08.
Array.addRange(arrayData, [“Hyundai”, “Acura”, “Suzuki”]);
09.
alert(arrayData.length);
10.
Array.remove(arrayData, “Suzuki”);
11.
Array.removeAt(arrayData, 1);
12.
Array.clear(arrayData);
While not the most useful example, it illustrates the new abilities ASP.NET AJAX extensions adds to work manipulate array data.
The ASP.NET AJAX extensions add additional capabilities in working with primitives. It extends the String, Number, Boolean, Date, etc. types to include additional functionality. Let’s look at some of the new string methods first. Below is an example of working with strings:
Listing 6: Processing text
01.function
processString(text)
02.
{
03. //There is also trimStart and trimEnd options too
04. var
input = text.trim();
05. if
(input.startsWith(“\’”))
06.
input = input.substring(1, input.length – 1);
07. if
(input.endsWith(“\’”))
08.
input = input.substring(0, input.length – 2);
09. if
(input.indexOf(“{0}”) > -1)
10.
input = input.format(“Welcome {0}!”, input);
11. return
input;
12.
}
Not all of the methods above are extended in the ASP.NET AJAX library; however, there are some useful additions. I personally enjoy the ability to use format strings through the format method. The format method is very handy in the .NET framework to insert data into prefabricated text, and now it’s available client-side.
In addition, the extensions add the startsWith
and endsWith
method for checking the start and end of the text for specific characters. There are several options for trimming text, either by using trim
(), trimStart
(), or trimEnd
(), which trim the start, the end, or both the start and end of the string.
Because data is often textual in nature, for integer data to be used property, it has to be of the right type. Some of the components in the AJAX control toolkit validate their parameters for correctness. In order to convert textual data to numerical form, use the following approaches:
Listing 7: Parsing Numbers
1.var
number1 = Number.parseInvariant(text); //culture agnostic
2.
alert(number1);
3.var
number2 = Number.parseLocale(text); //culture specific
4.
alert(number2);
Depending on whether your needs are a number for a specific culture or an invariant number (culture-agnostic), these two methods help convert textual data to a number. If, for some reason, the number isn’t valid, the constant NaN
is returned. For culture-specific formatting to work, set the ScriptManager’s EnableScriptGlobalization
to true, as well as configure the <globalization culture=”auto”>
element in the configuration file.
Boolean values have a similar utility for parsing, though culture specific functionality isn’t needed, therefore the method name is “parse” accordingly. Because the process is similar to above, I’ve left it out of the discussion.
ASP.NET AJAX components have the ability to throw errors whenever the conditions aren’t correct. For instance, if a parameter value is out of range or of the wrong type, errors can be thrown that are returned to the caller, similar to how the .NET framework works. Errors were in the JavaScript library; however, the ASP.NET AJAX extensions added several specific options for throwing errors.
For instance, to validate incoming data, the following could be used to ensure the input is correct (which isn’t possible in the example below):
Listing 8: Throwing errors
01.function
processText(text)
02.
{
03. if
(text == null
|| text === undefined)
04. throw
Error.argumentNull(“text”, “No value provided.”);
05. if
(text.length == 0)
06. throw
Error.argument(“text”, “Empty string”);
07. if
(text.length > 50)
08. throw
Error.argumentOutOfRange(“text”, text, “range issue”);
09. if
(text == “invalid”)
10. throw
Error.invalidOperation(“Invalid operation”);
11. if
(text == “not done”)
12. throw
Error.notImplemented();
13. var
err = Error.create(“Generic Error”);
14. throw
err;
15.
}
Errors are a normal way to express that a condition isn’t right. The above example doesn’t properly show that (throwing an exception in every case), but there are many options available when throwing errors. It’s possible to create a custom exception of your own, and append it to the Error object.
JavaScript also has the ability to catch errors using a try/catch
block like C#, which already exists in the JavaScript framework.
There are a new set of global methods available with the ASP.NET AJAX extensions. These global methods are shortcuts for performing common operations. For instance, the $get
method is a shortcut for document.getElementById
and retrieves a reference to the HTML element in the page. The $find
method, however, is a shortcut method for finding a specific component by its ID. This is a highly useful command to access the class for an AJAX control or extender. For instance, take a look at the following code snippet:
Listing 9: Accessing a TabContainer AJAX control using $find
01.
<script language=”javascript”>
02. function
pageLoad()
03.
{
04. var
tabs = $find(“<%= tabContainer.ClientID %>”);
05. if
(tabs.get_tabs().length > 1)
06.
tabs.set_activeTabIndex(1);
07.
}
08.
</script>
09.
..
10.
<asp:TabContainer id=”tabContainer” runat=”server”>
11.
..
12.
</asp:TabContainer>
The $find
method now contains a reference to the client class; every AJAX server control or extender has a client counterpart. The $find
method returns a reference to that client component which has its own ID value that matches the ID of the control. Depending on where in the lifecycle $find
is called, a null reference may be returned.
ASP.NET AJAX also has the ability to connect to a server and return data brought back from a web service or a static page method. The key to making this work is defining the service locally. What that means is the remote call has to be to the local web server; otherwise, an exception will be thrown. This is not an error; rather, it’s a feature. It’s designed this way for security purposes.
Making a call to the web server is done through the Sys.Net.WebServiceProxy class. Under the scenes, the class uses a Sys.Net.WebRequest object to connect to the web service/page method. If you are familiar with this object in .NET server framework, the System.Net.WebRequest object performs the work of connecting to a web resource, returning a WebResponse with the response from the requested system. The WebRequest/WebResponse objects have been used in examples of screen-scraping, where the contents of an HTML page are downloaded to the program and data is extracted from it.
I’m going to illustrate using the page method approach. As I said before, the WebServiceProxy can call a method defined in the page class. The requirements of this method are that it is defined as static, and that it is decorated with the WebMethod
attribute, as shown below:
Listing 10: Page method used in web service call
1.
[WebMethod]
2.public
static
string
GetCurrentDate()
3.
{
4. return
DateTime.Now.ToString();
5.
}
The date returned from the web service method is passed to a span element in the page. Take a look at the following definition.
Listing 11: ASPX that consumes page method
01.
<script language="javascript"
type="text/javascript"
>
02. function
pageLoad()
03.
{
04. var
wsProxy = new
Sys.Net.WebServiceProxy();
05.
wsProxy.set_timeout(0);
06. var
label = $get("displayText"
);
07. var
request = wsProxy._invoke("
http://localhost/testpage.aspx"
,
08. "GetCurrentDate"
, false
, {}, onSuccess, onFailure, label);
09.
}
10. function
onSuccess(result, userContext, methodName)
11.
{
12.
userContext.innerText = result;
13.
}
14. function
onFailure(result, userContext, methodName)
15.
{
16.
userContext.innerText = "Error"
;
17.
}
18.
</script>
19.
<span id="displayText"
></span>
The _invoke
method performs the actual work. Here the web service connects to the static page method on a page using the local web server. The _invoke
method also takes the name of the method (GetCurrentDate
), whether the request uses HTTP get, the parameters involved ({} meaning no parameters in this case; otherwise, a key/value pair is provided using key:value
format), and the callback/context information.
If the web service works successfully, the date will be displayed in the span; otherwise, the text error is displayed in the span.
This article, part 2 of the series, looks at some of the additional abilities that ASP.NET AJAX gives you, such as the use of descriptors, type information, and new objects like Error, Array, String, Number, etc. It also looked into making web service calls to a static page method. All of these features are keys to developing a rich AJAX user experience
.