Asp.Net Ajax Client Network Calls Techniques With WebRequest & WebRequestManager

Ajax Network Calls is almost being most extensively used on web application. Client calls a page on Url via javascript and the Url’s content is being stored in a variable as a string.
This variable can be written on html element like div element. Traditional ajax is basically a network call.

We can use ajax network call technique to populate combo box or select element from database, Auto complete function, search records, update, insert record etc.

I’ll give examples of ajax network calls techniques using client script Sys.Net.WebRequest class. We will use this client side class in javascript.
Remember that we have to put ScriptManager control in aspx page to enable Asp.Net ajax extension.

Web Request Example

I have two textboxes which their ids are txname and txage. After user enters his/her name, age and clicks “Go” button, current date and time will be displayed in div element along with entered values in each textboxes.


Full source code:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script language="javascript" type="text/javascript">
        function _go() {
           
            var request = new Sys.Net.WebRequest();
            request.set_url("ajax_handler.ashx");
            request.set_httpVerb("POST");
            var body = "txname=" + $get("txname").value + "&txage=" + $get("txage").value;
            request.set_body(body);
           
            request.add_completed(go_completed);
            request.invoke();
        }

        function go_completed(executor, eventargs) {
            if (executor.get_responseAvailable()) {
                $get("result").innerHTML = executor.get_responseData();
            }
        }
        
        if (typeof (Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
    </script>
</head>
<body>
    <form id="form1" runat="server" >
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
    Name: <input type="text" id="txname" name="txname" /> &nbsp;Age: <input type="text" id="txage" name="txage" size="5" /> &nbsp;<input type="button" id="btn" name="btn" value="Go"  onclick="_go()" />
    <br />
    <div id="result"></div>
    </div>
    </form>
</body>
</html>

If user clicks “Go” button then _go() function is running and the webrequest instance is created.

The code of Webrequest instance Initialization and setting several properties also to invoke is below

function _go() {
var request = new Sys.Net.WebRequest();
request.set_url("ajax_handler.ashx");
request.set_httpVerb("POST");
var body = "txname=" + $get("txname").value + "&txage=" + $get("txage").value;
request.set_body(body);
request.add_completed(go_completed);
request.invoke();
}

Use var request = new Sys.Net.WebRequest(); to create Webrequest instance.

Set webrequest target Url to generic handler file “ajax_handler.ashx”, POST submit method is used by ‘set_httpVerb’, parameters also set by ‘set_body’. The go_completed() function is a completed handler for this instance.
This go_completed() function is registered by ‘add_completed’ method. ‘invoke’ method is invoking webrequest to run.

FYI, generic handler is a .ashx file and it doesnt have any web UI elements. So the main purpose of generic handler is to process something not to view html presentation. However we can generate html elements / presentation from server code via context.Response.Write() method inside generic handler.
In fact, examples which I have are using generic handler to generate html presentation more often.

I am passing parameters via key value pairs like usual Url parameter passing method. Also I use POST submit method so that I’ll use context.Request.Form inside generic handler to retrieve their values.

If WebRequest ends its process then go_completed(..) function is running.

function go_completed(executor, eventargs) {
if (executor.get_responseAvailable()) {
$get("result").innerHTML = executor.get_responseData();
}
}

Every Webrequest completed handler function has two arguments, ‘executor’ and ‘eventargs’. These arguments has not being registered in any method, it is just exist there. So we can write them straight as completed handler arguments.
If response data or contents of target Url is available, executor.get_responseAvailable() equals to true and then “result” div is filled in with executor response data by executor.get_responseData() which means WebRequest process result.
Take a not that response data is a content of target Url.

This Ajax network calls target Url is a generic handler Url “ajax_handler.aspx”. Here’s its source code:

Imports System
Imports System.Web

Public Class ajax_handler : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        context.Response.ContentType = "text/html"
        context.Response.Write("Your process finished on " & DateTime.Now.ToString() & "<br>")
        context.Response.Write("With Data : " & context.Request.Form("txname") & " " & context.Request.Form("txage"))
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property
End Class

The template body of above source code is auto generated by VS 2010. I only write on ProcessRequest(...) procedure.

We can specify the content type of generic handler to ‘text/plain’, ‘text/html’ etc by using context.Response.ContentType = "text/html".
I write a string along with current process datetime and posted data which are txname and txage inside ‘ProcessRequest’ procedure using context.Response.Write(..).
I retrieve each posted data value with context.Request.Form(..).

If execution of this “ajax_hander.ashx” is completed then go_completed(..) runs. “ajax_hander.ashx” content is retrieved as webrequest instance response data and display that content in div element.

So we have two main files in general which are .aspx (contains input elements and javascript) and .ashx (logic process) files with not to mention .aspx.vb file because we use client script to do ajax network calls.

Many User Inputs Example

Previous example is only used two posted data from textboxes which are txname and txage.

How about if we have many inputs entered by users? Not only textboxes but select element, radio button, and checkbox elements. We need to consider how to handle many parameters that are being passed to the Url.
As default, we should write long key value pairs string in the body of webrequest instance which is not effective if we have to write that long string piece by piece. We need a client script function to generate that body string.

In this example, we have two textboxes, one combobox or select element, two radio buttons and four checkboxes. User clicks “Go” button and data entered by user will be displayed in div element.
I divide the layout to two columns with help of table. Table’s left side contains input boxes and its right side contains the result div element.

Full source code:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript">
        function form_serialization() {
            var str_body = "";
            for (var i = 0; i < $get("form1").elements.length; i++) {
                var el_name = $get("form1").elements[i].name;
                var el_value = $get("form1").elements[i].value;
                switch ($get("form1").elements[i].type) {
                    case "text":
                    case "hidden":
                        if (el_name !== "__EVENTTARGET" && el_name !== "__EVENTARGUMENT" && el_name !== "__VIEWSTATE") {
                            str_body = str_body + "&" + el_name + "=" + el_value;
                        }
                        break;
                    case "select-one":
                        str_body = str_body + "&" + el_name + "=" + el_value;
                        break;
                    case "radio":
                    case "checkbox":
                        if ($get("form1").elements[i].checked) {
                            str_body = str_body + "&" + el_name + "=" + el_value;
                        }
                        break;
                }


            }
            str_body = str_body.substring(1);
            return str_body;
        }

        function _go() {

            var request = new Sys.Net.WebRequest();
            request.set_url("ajax_handler2.ashx");
            request.set_httpVerb("POST");
            var body = form_serialization();
            request.set_body(body);

            request.add_completed(go_completed);
            request.invoke();
        }

        function go_completed(executor, eventargs) {
            if (executor.get_responseAvailable()) {
                $get("result").innerHTML = executor.get_responseData();
            }
        }


        if (typeof (Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    
    <table>
    <tr valign="top">
        <td>
            Name: <input type="text" id="txname" name="txname" /> &nbsp;Age: <input type="text" id="txage" name="txage" size="5" /> <br /><br />
            Gender: <select name="gender">
                <option value='Male'>Male</option>
                <option value='Female'>Female</option>
            </select> &nbsp;
            Own a Car ? <input type="radio" name="rdocar" value="yes" />Yes &nbsp; <input type="radio" name="rdocar" value="no" />No
            <br /><br />
            Favourite books:<br />
            <input type="checkbox" name="book" value="VB" />VB<br />
            <input type="checkbox" name="book" value="C#" />C#<br />
            <input type="checkbox" name="book" value="PHP" />PHP<br />
            <input type="checkbox" name="book" value="Java" />Java
            <br /><br />
            <input type="button" id="btn" name="btn" value="Go"  onclick="_go()" />
        </td>
        <td width="10">&nbsp;</td>
        <td>
            <div id="result"></div>
        </td>
    </tr>
    </table>
    </div>
    </form>
</body>
</html>

I have client script function, form_serialization(). This function is used to look at all html user input elements and return key value pairs string. Key means ‘name’ of element and ‘value’ is element’s value. In other words, this function iterates all elements inside a form tag to create key value pairs string.
Please take a note that asp.net generates automatically three hidden elements which are __EVENTTARGET, __EVENTARGUMENT, __VIEWSTATE, so we can exclude those hidden elements value from key value pairs creation.
Also we have radio buttons and checkboxes that only checked elements that being posted. You can make a separate Js file containing this client script function so that this function can be re-used on another page.

If user clicks “Go” button then _go() function runs and so webrequest instance is created.

function _go() {
var request = new Sys.Net.WebRequest();
request.set_url("ajax_handler2.ashx");
request.set_httpVerb("POST");
var body = form_serialization();
request.set_body(body);

request.add_completed(go_completed);
request.invoke();
}

The ajax network calls target Url is a generic handler “ajax_hander2.ashx”. The webrequest body contains form serialization.
This body value generated via form_serialization() method.

At the end of process go_completed(..) function is running.

function go_completed(executor, eventargs) {
if (executor.get_responseAvailable()) {
$get("result").innerHTML = executor.get_responseData();
}
}

Content of generic handler or webrequest instance response data is displayed inside a div element with id=”result”.

The ajax_handler2.ashx code:

Imports System
Imports System.Web

Public Class ajax_handler2 : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        context.Response.ContentType = "text/html"
        With context
            .Response.Write("Your process finished on " & DateTime.Now.ToString() & "<br>")
            .Response.Write("With Data:<br> Name: " & .Request.Form("txname") & ", Age: " & .Request.Form("txage") & "<br>")
            .Response.Write("Gender: " & .Request.Form("gender") & ", Own A Car: " & .Request.Form("rdocar") & "<br>")
            .Response.Write("Favourite books: <br>")
           
            .Response.Write(.Request.Form("book"))
        End With
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property
End Class

This generic handler code template body is auto generated by VS 2010. I write my own codes inside the ProcessRequest procedure.
I use With context ... End With to shorten my codes. It means that I dont have to use full sentence like context.Response.Write(..) or context.Request.Form(..).
Using this With context ... End With, I can only write .Response.Write(..) and .Request.Form(..) inside the ‘With’ clause without ‘context’ anymore.

If user checks a favorite book more than one checkboxes then its value is a string separated by comma. So if you choose you favorite books are VB, C#, and PHP then book checkbox element value is “VB,C#,PHP”.
You can see this web app result at screen shot picture above.

Sys.Net.WebRequestManager Example

This Sys.Net.WebRequestManager class manages WebRequest instance. We can set all WebRequests time out, registers invoking request client handler function, and reqisters completed client handler function. Also this WebRequestManager class can executes a WebRequest.
Take a note that a “client handler” words means are different with “generic handler” that I have previously. Generic handler is a server asp.net handler.

Registered invoking and completed handler function runs on every WebRequest inside page that have WebRequestManager. So these are like global handler functions. We dont have to write/register a function on each WebRequest instance creation.

In this example, I’ve already set up a WebRequestManager time out to 1000 milliseconds on pageLoad event. This time out value can be changed by entering new time out value and click a “Set Time Out” button.
I have second button to process an ajax network calls. Webrequest instance triggers via WebRequestManager. If the process takes longer time than time out value then “Timed out” message will be appear.

Otherwise, if time out value is longer than process time then “Hello World” message will be showed.

Full source code:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="webreqmng.aspx.vb" Inherits="webreqmng" %>

<!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></title>
    <script type="text/javascript">
        function pageLoad() {
            Sys.Net.WebRequestManager.set_defaultTimeout(1000);
            Sys.Net.WebRequestManager.add_invokingRequest(invokingHandler);
            Sys.Net.WebRequestManager.add_completedRequest(completedHandler);
        }

        function _settimeout() {
            Sys.Net.WebRequestManager.set_defaultTimeout($get("txtimeout").value);
            alert("Time out has been set to " + $get("txtimeout").value + " milli sec");
        }

        function _process() {
            var request = new Sys.Net.WebRequest();
            request.set_url("TimedSleep.ashx");
            Sys.Net.WebRequestManager.executeRequest(request);
        }

        function invokingHandler() {
            $get("updprogress").style.display = "block";
            $get("result").style.visibility = "hidden";
        }

        function completedHandler(executor, eventargs) {
            $get("updprogress").style.display = "none";
            $get("result").style.visibility = "visible";
            if (executor.get_timedOut()) {                 
                $get("result").innerHTML = "Timed out !";
            }

            if (executor.get_responseAvailable()) {
               
                $get("result").innerHTML = executor.get_responseData();
            }
        }

        if (typeof (Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <ol>
        <li>Current Timeout (milli sec): <input type="text" id="txtimeout" size="6" value="1000" /> &nbsp;<input type="button" id="btnsettimeout" value="Set Time Out" onclick="_settimeout()" /></li>
        <li><input type="button" id="btnstart" value="Start Ajax" onclick="_process()" /></li>
        </ol>       
       
        <div id="updprogress" style="display:none">Loading ..</div>
        <div id="result" style="background-color:Yellow;width:300px;visibility:hidden"></div>
    </div>
    </form>
</body>
</html>

At pageLoad event, I set up the time out to 1000 milliseconds or 1 second by using below code

function pageLoad() {
Sys.Net.WebRequestManager.set_defaultTimeout(1000);
Sys.Net.WebRequestManager.add_invokingRequest(invokingHandler);
Sys.Net.WebRequestManager.add_completedRequest(completedHandler);
}

Sys.Net.WebRequestManager.set_defaultTimeout(..) will set every WebRequest time out. I use Sys.Net.WebRequestManager.add_invokingRequest(..) method to register WebRequest invoke handler function, invokingHander.
Also I use Sys.Net.WebRequestManager.add_completedRequest(..) method to register Webrequest completed handler function, completedHandler. So we have to have those handler functions in this page.

We can change time out value by entering new value to time out text box and click “Set Time out” button.
This “Set time out” button raises _settimeout() function. This function has same way to set time out, Sys.Net.WebRequestManager.set_defaultTimeout(..).

I have “updprogress” div element contains “Loading ..” message. At first time page load this div display style is set to none so it is not visible. If WebRequest process begins then this “updprogress” div will be visible.
Invoke handler function will do this.

function invokingHandler() {
$get("updprogress").style.display = "block";
$get("result").style.visibility = "hidden";
}

invokingHandler method executes when WebRequest is begin. The code $get("updprogress").style.display = "block"; makes “updprogress” div visible. So “Loading..” message appears on screen. On the other hand, “result” div element is hidden.
The “result” div is used as container of ajax network calls target Url’s content or response data. When request is begin this “result” div is not necessary until request is completed.

completedHandler function does opposite with invoke handler. If WebRequest ends a process then this function is running.

function completedHandler(executor, eventargs) {
$get("updprogress").style.display = "none";
$get("result").style.visibility = "visible";
if (executor.get_timedOut()) {
$get("result").innerHTML = "Timed out !";
}

if (executor.get_responseAvailable()) {

$get("result").innerHTML = executor.get_responseData();
}
}

“updprogress” div display style is set to none again and “result” div is visible inside completedHandler. This function has two arguments which are executor and event args.
Every WebRequest completed handler have these two arguments. So we can write them straight as function arguments without have to regiter them in WebRequestManager before hand.

executor.get_timedOut() returns true or false indicates this process is timed out or not. If it is timed out then “result” div element contains “Timed out !” message.
Otherwise, if result is ready or executor.get_responseAvailable() is equals to true then response data will be showed in “result” div via $get("result").innerHTML = executor.get_responseData();.

“Start Ajax” button raises _process() function.

function _process() {
var request = new Sys.Net.WebRequest();
request.set_url("TimedSleep.ashx");
Sys.Net.WebRequestManager.executeRequest(request);
}

I create a new webrequest instance and set its target Url to a server generic function “TimedSleep.ashx” inside _process() method. Also I write Sys.Net.WebRequestManager.executeRequest(..); to make a webrequest instance running.

“Timedsleep.ashx” generic function code:

Imports System
Imports System.Web

Public Class TimedSleep : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        context.Response.ContentType = "text/html"
        System.Threading.Thread.Sleep(2500)
        context.Response.Write("Hello World")
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property
End Class

This server generic handler sleeps for 2500 milliseconds or 2.5 seconds before it writes a Hello World string.

Remember that we set time out to 1000 milliseconds so that webrequest will be timed out except that we change time out value longer than 2500 milliseconds.

JSON Usage Example

All previous ajax network calls techniques examples in this post returns only few string data. Now, I give you example on how to return a lot of data from ajax network calls and handle them. I get the data source from database.
We can make a real web application by combining many user input boxes and returning lot of data records.

I use JSON string format as container of database record. JSON is abbreviation of JavaScript Object Notation. The JSON string can be parsed into Javascript object.
In general, webrequest calls a target Url, this Url retrieves records from database and display data as JSON format string. So the webrequest response data will be string of JSON.
This response data will be parsed to create Javascript object and so we can use that object to show data to html elements such as select box, unordered/ordered list, table etc.

A brief example creating and using JSON is below:

function jsonIntro() {
	var user = { "name": "Tom", "gender": "Male", "birthday": "1983-8-8" };
	document.write("Name: " + user.name + ", Gender: " + user.gender + ", Birthday: " + user.birthday);

	document.write("<br>-----<br>");

	var userlist = [{ "user": { "name": "Tom", "gender": "Male", "birthday": "1983-8-8"} }, { "user": { "name": "Lucy", "gender": "Female", "birthday": "1984-7-7"}}];
	for (var i = 0; i < userlist.length; i++) {
		var objuser = userlist[i].user;
		document.writeln("Name: " + objuser.name + ", Gender: " + objuser.gender + ", Birthday: " + objuser.birthday + "<br>");
	}
}

As you can see that I access ‘user’ variable like an object or class instance such as user.name, user.gender, and user.birthday. This can be done because of user variable contains formatted string with combination of ‘{‘, ‘:’, ‘,’.
This formatted string much like key value pairs with format “”:”” and separated by comma.

If you have more than one of array’s index like ‘userlist’ variable in jsonIntro() then you can access json object with index like this var objuser = userlist[i].user;.

In this Asp.Net JSON Usage example, I use Northwind sample Database to show product categories and related products. Categories data is listed on select or combo box. If user selects one of categories from that combo box then related products will be showed in unordered list.

Full source code:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript">
        function pageLoad() {
            Sys.Net.WebRequestManager.add_invokingRequest(invokingHandler);
            Sys.Net.WebRequestManager.add_completedRequest(completedHandler);

            loadcategories();
        }

        function loadcategories() {
            var request = new Sys.Net.WebRequest();
            request.set_url("json_handler.ashx");
            request.set_body("opt=categories");
            request.set_httpVerb("POST");
            request.set_userContext("categories");
            
            Sys.Net.WebRequestManager.executeRequest(request);
        }

        function invokingHandler() {
            $get("updprogress").style.display = "block";

        }

        function completedHandler(executor, eventargs) {
            updprogress.style.display = "none";
            var jsonstring;
            if (executor.get_responseAvailable()) {
                jsonstring = executor.get_responseData();
                var json_categ = eval("(" + jsonstring + ")");
                //alert(jsonstring);
                if (executor.get_webRequest().get_userContext() == "categories") {
                    var selector = document.createElement("select");
                    selector.onchange = function () {
                        load_products($get("categories").value);
                    };
                    selector.id = "categories";
                    div_categories.appendChild(selector);

                    var option = document.createElement("option");
                    option.value = "";
                    option.appendChild(document.createTextNode("-"));
                    selector.appendChild(option);

                    for (var i = 0; i < json_categ.length; i++) {
                        option = document.createElement("option");
                        option.value = json_categ[i].ID;
                        option.appendChild(document.createTextNode(json_categ[i].Name));
                        selector.appendChild(option);
                    }
                } else if (executor.get_webRequest().get_userContext() == "products") {
                    var ul = document.createElement("ul");
                    var li;

                    for (var i = 0; i < json_categ.length; i++) {
                        li = document.createElement("li");
                        li.appendChild(document.createTextNode(json_categ[i]));
                        ul.appendChild(li);
                    }
                    if (div_products.hasChildNodes() == false) {
                        div_products.appendChild(ul);
                    } else {
                        div_products.removeChild(div_products.lastChild);
                        div_products.appendChild(ul);
                    }
                }
            }
        }

        function load_products(optvalue) {
            var request = new Sys.Net.WebRequest();
            request.set_url("json_handler.ashx");
            request.set_body("opt=products&categid=" + optvalue);
            request.set_httpVerb("POST");
            request.set_userContext("products");

            Sys.Net.WebRequestManager.executeRequest(request);
        }

        if (typeof (Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
    Select a Category: <span id='div_categories'></span>
    <div id="updprogress" style="display:none">Loading ..</div>
    <div id='div_products'></div>

    </div>
    </form>
</body>
</html>

WebRequestManager registers invoke and completed handler functions at pageLoad and also the select box is loaded with product Categories by loadcategories() method.

function loadcategories() {
var request = new Sys.Net.WebRequest();
request.set_url("json_handler.ashx");
request.set_body("opt=categories");
request.set_httpVerb("POST");
request.set_userContext("categories");

Sys.Net.WebRequestManager.executeRequest(request);
}

This loadcategories() method create webrequest instance, set target Url to json_handler.ashx, set body with key value pair, and set user context to “categories”. This user context is used to differentiate between loading categories or products.

Lets take a look at source code of json_handler.aspx because of when page is loaded then json_handler.ashx is invoked.

Imports System
Imports System.Web
Imports System.Data.SqlClient
Imports System.Data
Imports System.Text

Public Class json_handler : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        context.Response.ContentType = "text/plain"
        Dim conn As New SqlConnection("Data Source=.\SQLDEV;Initial Catalog=Northwind;Integrated Security=true;")
        conn.Open()
        Dim cmd As New SqlCommand()
        cmd.Connection = conn
        If (context.Request.Form("opt") = "categories") Then
            cmd.CommandText = "select CategoryID, CategoryName from Categories"
        Else
            cmd.CommandText = "select ProductName from Products where CategoryID=" & context.Request.Form("categid")
        End If
        
        
        Dim da As New SqlDataAdapter(cmd)
        Dim dt As New DataTable()
        da.Fill(dt)
        
        Dim sb As New StringBuilder()
        For i As Integer = 0 To dt.Rows.Count - 1
            If (context.Request.Form("opt") = "categories") Then
                If i > 0 Then sb.Append(",")
                If i = 0 Then
                    sb.Append("[")
                    sb.Append("{""ID"":""" & dt.Rows(i)(0).ToString() & """,""Name"":""" & dt.Rows(i)(1).ToString() & """}")
                ElseIf i = dt.Rows.Count - 1 Then
                    sb.Append("{""ID"":""" & dt.Rows(i)(0).ToString() & """,""Name"":""" & dt.Rows(i)(1).ToString() & """}")
                    sb.Append("]")
                Else
                    sb.Append("{""ID"":""" & dt.Rows(i)(0).ToString() & """,""Name"":""" & dt.Rows(i)(1).ToString() & """}")
                
                End If
            Else
                If i > 0 Then sb.Append(",")
                If i = 0 Then
                    sb.Append("[")
                    sb.Append("""" & dt.Rows(i)(0).ToString() & """")
                ElseIf i = dt.Rows.Count - 1 Then
                    sb.Append("""" & dt.Rows(i)(0).ToString() & """")
                    sb.Append("]")
                Else
                    sb.Append("""" & dt.Rows(i)(0).ToString() & """")
                
                End If
            End If
        Next
        context.Response.Write(sb.ToString())
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property
End Class

I connect to Northwind database and query the categories / products table’s data. It is depend on “opt” variable value whether it is categories or products.
I put the data in DataTable class and iterate DataTable rows to create JSON string. I use StringBuilder class as container of that JSON because of using StringBuilder is more memory efficient than using regular string variable.

At the end of webrequest process, the completed handler is executing and catch the returned JSON string.

function completedHandler(executor, eventargs) {
	updprogress.style.display = "none";
	var jsonstring;
	if (executor.get_responseAvailable()) {
		jsonstring = executor.get_responseData();
		var json_categ = eval("(" + jsonstring + ")");
	   
		if (executor.get_webRequest().get_userContext() == "categories") {
			var selector = document.createElement("select");
			selector.onchange = function () {
				load_products($get("categories").value);
			};
			selector.id = "categories";
			div_categories.appendChild(selector);

			var option = document.createElement("option");
			option.value = "";
			option.appendChild(document.createTextNode("-"));
			selector.appendChild(option);

			for (var i = 0; i < json_categ.length; i++) {
				option = document.createElement("option");
				option.value = json_categ[i].ID;
				option.appendChild(document.createTextNode(json_categ[i].Name));
				selector.appendChild(option);
			}
		} else if (executor.get_webRequest().get_userContext() == "products") {
			....
		}
	}
}

I get the Json string value by jsonstring = executor.get_responseData(); and do var json_categ = eval("(" + jsonstring + ")"); to convert it to Javascript object.

Check whether the userContext is categories or not and if it is categories then I create select element by var selector = document.createElement("select");.

Iterate that Json object members from response data and populate its values to options and append it to select element and so Categories list is done.

If user change categories selection then load_products(..) function is running.

function load_products(optvalue) {
var request = new Sys.Net.WebRequest();
request.set_url("json_handler.ashx");
request.set_body("opt=products&categid=" + optvalue);
request.set_httpVerb("POST");
request.set_userContext("products");

Sys.Net.WebRequestManager.executeRequest(request);
}

This method creates webrequest instance and its target Url is still json_handler.ashx but its body set to opt=products&categid= and userContext is products.

Json_handler.ashx queries products table data, store it to DataTable class, and iterates DataTable row to create JSON string.

If webrequest ends the process then completedHandler(..) is running.

function completedHandler(executor, eventargs) {
	....
	if (executor.get_responseAvailable()) {
		jsonstring = executor.get_responseData();
		var json_categ = eval("(" + jsonstring + ")");
		
		if (executor.get_webRequest().get_userContext() == "categories") {
			.....
		} else if (executor.get_webRequest().get_userContext() == "products") {
			var ul = document.createElement("ul");
			var li;

			for (var i = 0; i < json_categ.length; i++) {
				li = document.createElement("li");
				li.appendChild(document.createTextNode(json_categ[i]));
				ul.appendChild(li);
			}
			if (div_products.hasChildNodes() == false) {
				div_products.appendChild(ul);
			} else {
				div_products.removeChild(div_products.lastChild);
				div_products.appendChild(ul);
			}
		}
	}
}

This completedHandler is a global webrequest completed handler function because we already registered it at pageLoad event by Sys.Net.WebRequestManager.add_completedRequest(completedHandler);.
Either loadcategories or load_products webrequest has this completed handler.

Response data as JSON string comes from json_handler.ashx is converted to Javascript Object. Then the handler checks the webrequest userContext whether it is categories or products which in this case is products.

This handler create un-ordered list and fill in the data with each JSON object value.

Summary

Asp.Net Ajax Network Calls techniques using Sys.Net.WebRequest client script class.
All parameters that are key value pairs sent to target Url must be serialize. We can make a shared function to do that.
Server generic handler .ashx file as target Url is more preferably than .aspx file because of generic handler as default does not contains any presentation elements except that we generated it.
JSON is used to handle bunch of database records in target Url. Target Url contains JSON string. If webrequest process is completed then webrequest’s response data will have this string and then it will be converted to Javascript object.
So we can treat that JS object like an class or array.

There are alternatives way to do Ajax Network Calls, using WebService and WCF techniques but I am not explaining about those in this post.

Best Regards,
Agung Gugiaji

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s