AJAX .Net Wrapper usage guide
Creating the Server-Side Functions
Registering functions in another class
Background
Asynchronous JavaScript and XML (AJAX) has recently become the craze thanks, in no small part, to Google’s usage of it in Google Suggest as well as Google Maps. In ASP.Net terms,
Enter Michael Schwarz's
It should be pointed out that technologies such as
| To learn more about |
How it works - Overview
The wrapper itself works by marking .Net functions as
Complicated? It isn't. Let's look at a simplified example. Given the .Net function:
'VB.Net public function Add(firstNumber as integer, secondNumber as integer) as integer return firstNumber + secondNumber end sub |
//C# public int Add(int firstNumber, int secondNumber) { return firstNumber + secondNumber; } |
The
Initial Setup
We'll first go through the steps of "installing" the .dll for use in your project. If you know how to add a reference to a .dll file, skip this section.
First, if you don’t already have it, download the latest version of AJAX. Unzip the downloaded file and place the ajax.dll within a ref folder of your project. In Visual Studio.Net, right click the "References" node in the Solution Explorer and select Add Reference. In the newly opened dialog, click Browse and navigate to the ref/ajax.dll file. Click Open followed by Ok. You are now ready to start programming with the
| If you’re having difficulty setting up the reference, check out: |
Setting up the HttpHandler
The first step necessary to make everything work is to set up the wrapper's HttpHandler in the web.config. Without going into detailed explanation of what and how HttpHandlers work, it's sufficient to know that that they are used to process ASP.Net requests. For example, all requests for *.aspx pages are handled by the System.Web.UI.PageHandlerFactory class. Similarly we'll make all requests to
... |
The above code basically tells ASP.Net that any requests made that match the specified path (
Setting up the Page
We are now ready to start coding. Create a new page, or open an existing one and in the code behind file, add the following code in the Page_Load event:
'vb.net Public Class Index Inherits System.Web.UI.Page Private Sub Page_Load(sender As Object, e As EventArgs) Handles MyBase.Load Ajax.Utility.RegisterTypeForAjax(GetType(Index)) '... end sub '... End Class |
//C# public class Index : System.Web.UI.Page{ private void Page_Load(object sender, EventArgs e){ Ajax.Utility.RegisterTypeForAjax(typeof(Index)); //... } //... } |
The call to RegisterTypeForAjax emits the following JavaScript on the page (alternatively, you could manually place the following two lines on the page):
|
Where the bolded parts have the following meaning:
NAMESPACE.PAGECLASS | The namespace and class of the current page (this will typically be the value of the Inherits attribute in the @Page directive) |
ASSEMBLYNAME | The name of the assembly the current page is part of (this will typically be the name of your project) |
Bellow is a sample output for the sample.aspx page in an AjaxPlay project:
<%@ Page Inherits="AjaxPlay.Sample" Codebehind="sample.aspx.cs" ... %>
|
You can test that everything is working properly by manually navigating to the src paths in your browser (view source and copy and paste the paths). If both paths output some (seemingly) meaningless text, you’ve done well so far. If they’re outputting nothing or ASP.Net errors, something was improperly done.
Even if you don’t know how HttpHandlers work, the above should be understandable. Via the web.config, we’ve made sure that all requests that go to
Creating the Server-Side Functions
We’ll now create a server-side function that’ll be asynchronously be available from a client-side call. Since not all return types are currently supported (don’t worry, upcoming versions will build on what’s currently there), we’ll stick with our simple ServerSideAdd functionality. In the code behind file, add the following method to your page class:
'VB.Net Public Function ServerSideAdd (byval firstNumber As Integer, byval secondNumber
Return firstNumber + secondNumber End Function |
//C# [Ajax.AjaxMethod()] public int ServerSideAdd(int firstNumber, int secondNumber) { return firstNumber + secondNumber; } |
Note that the functions have the Ajax.AjaxMethod attribute set. The attribute serves to tell that wrapper to create JavaScript proxies for these methods so that they might be called client-side.
Making our client-side call
The last step is to call the function using JavaScript. The
<%@ Page Inherits="AjaxPlay.Sample" Codebehind="sample.aspx.cs" ... %>
|
Of course, we’ll want to use this powerful capability for more than simply alerting the user. That’s why all client-side proxies (such as the JavaScript Sample.ServerSideAdd function), also accept an additional property. The property is the callback function called in order to process the response:
Sample.ServerSideAdd(100,99, ServerSideAdd_CallBack);
function ServerSideAdd_CallBack(response){ if (response.error != null){ alert(response.error); return; } alert(response.value); } |
We can see from the above code that we’ve specified an extra parameter. ServerSideAdd_CallBack (also shown above) is the client-side function used to process the response from the server. The callback function receives a response object which exposes three key properties:
value | The actual return value (be it a string, custom object or dataset) of the server-side function. |
error | An error message, if any. |
request | The raw response from the xml http request. |
context | A context object. |
First we check the error value to see if any errors occurred. You can easily play with the error property by throwing an exception in the server-side function. Then, in this simplified case, we alert the value. The request property can be used to get additional information (see box bellow).
| To learn more about the Xml Http request, check out the following link dump: http://www.quirksmode.org/blog/archives/2005/02/xmlhttp_linkdum.html |
Dealing with Types
Returning complex types
The
Returned DataSets work much like real .Net DataSet. Given a server side function which returns a DataSet, we could display the contents client side via:
|
[Serializable()] public class User{ private int _userId; private string _firstName; private string _lastName; public int userId{ get { return _userId; } } public string FirstName{ get { return _firstName; } } public string LastName{ get { return _lastName; } } public User(int _userId, string _firstName, string _lastName){ this._userId = _userId; this._firstName = _firstName; this._lastName = _lastName; } public User(){} [AjaxMethod()] public static User GetUser(int userId){ //Replace this with a DB hit or something :) return new User(userId,"Michael", "Schwarz"); } } |
We would register the GetUser proxy via a call to the RegisterTypeForAjax:
private void Page_Load(object sender, EventArgs e){ Utility.RegisterTypeForAjax(typeof(User)); } |
Allowing us to asynchronously call the GetUser in client-side code with code such as:
|
The value returned in the response is actually an object which exposes the same properties as a server-side object (FirstName, LastName and UserId).
Custom Converters
As we’ve seen, the
This guide will be updated with additional information on custom converters shortly (sorry).
Miscellaneous
Registering functions in another class
In the above example, our server-side functions resided within the code behind of the executing page. However, there’s no reason why these functions can’t be in a separate class file. Remember, the way the wrapper works is to find all methods within the specified class that have the
Public Class AjaxFunctions Public Function Validate(username As String, password As String) As Boolean 'do something 'Return something End Function End Class |
We could have the
'Vb.Net Private Sub Page_Load(sender As Object, e As EventArgs) Handles MyBase.Load Ajax.Utility.RegisterTypeForAjax(GetType(AjaxFunctions)) '... End Sub |
//C# private void Page_Load(object sender, EventArgs e){ Ajax.Utility.RegisterTypeForAjax(typeof(AjaxFunctions)); //... } |
Remember, the client-side proxy takes the name of
How the proxy really works
The second script tag generated by the
Returning Unicode characters
[Ajax.AjaxMethod] public string Test1(string name, string email, string comment){ string html = ""; html += "Hello " + name + " html += "Thank you for your comment "; html += System.Web.HttpUtility.HtmlEncode(comment); html += "."; return html; } |
SessionState
It’s likely that you’ll need to access session information in your server side function. To do so, you must simply tell
While looking at the session capabilities of the wrapper, let’s look at a couple other features. In this example, we have a document management system which puts a lock on a document while a user is editing it. Other users can request to be notified when the document because available. Without
First we’ll write our server side function, the goal of which is to loop through the documentIds the user wishes to edit (stored in a session) and return all released documents.
'Vb.Net Public Function DocumentReleased() As ArrayList If HttpContext.Current.Session("DocumentsWaiting") Is Nothing Then Return Nothing End If Dim readyDocuments As New ArrayList Dim documents() As Integer = CType(HttpContext.Current.Session("DocumentsWaiting"), Integer()) For i As Integer = 0 To documents.Length - 1 Dim document As Document = document.GetDocumentById(documents(i)) If Not document Is Nothing AndAlso document.Status = DocumentStatus.Ready Then readyDocuments.Add(document) End If Next Return readyDocuments End Function |
//C# [Ajax.AjaxMethod(HttpSessionStateRequirement.Read)] public ArrayList DocumentReleased(){ if (HttpContext.Current.Session["DocumentsWaiting"] == null){ return null; } ArrayList readyDocuments = new ArrayList(); int[] documents = (int[])HttpContext.Current.Session["DocumentsWaiting"]; for (int i = 0; i <> Document document = Document.GetDocumentById(documents[i]); if (document != null && document.Status == DocumentStatus.Ready){ readyDocuments.Add(document); } } return readyDocuments; } } |
Notice that we specify the HttpSessionStateRequirement.Read value (alternatives being Write and ReadWrite).
Now we write our JavaScript to take advantage of this method:
onload="setTimeout('Document.DocumentReleased(DocumentsReady_CallBack)', 10000);"> |
Our server side function is called once on page load and subsequently every 10 seconds. The call back function checks the response to see if any values were returned, and if so displays the newly available documents to the user in a div tag.
Conclusion
| Keep a close eye on the |
| For a good hands-on sample, check out the following demo application: |
No comments:
Post a Comment