Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

ASP.NET Ajax Solution by Jquery and JSON

4.00/5 (5 votes)
4 Oct 2011CPOL5 min read 43.3K  
ASP.NET Ajax solution by Jquery and JSON

Introduction

I will share my Ajax solution by Jquery with JSON format in the next two parts. In the first part, I will describe how to implement Jquery Ajax call in the ASP.NET page.
In the second part, I will describe my Ajax datagrid user control that implements Jquery and Ajax call with JSON format.

Background

The reason that we don't use Microsoft Ajax library is that we try to avoid the transparent code which is provided by Microsoft and also get flexibility to handle code and logic by ourselves, so that we can keep the code lighter and easier to manage and high performance, on the other hand, we will use Jquery library, because it has become popular and more like a standard.

You might see similar solutions somewhere else, I combined them together with my idea and make them work.

Summary

In short, the Ajax route is client fire Ajax call request, the request includes the function name that will be called in server side and the parameters and the callback function name, then the server processes the request and returns string result back to client. The result is serialized as JSON format string if it is not value type.

Step by Step

To make the route clear, I will demo it step by step:

Step 1: Reference Jquery

As I mentioned, we will implement Jquery library and its Ajax call. then we need load Jquery libraries on our pages first.
To import the Jquery, you can reference it in your master page or your page header or a header user control.

HTML
<HEAD runat="server">
      ......your other code......
      <script type="text/javascript" 
           src="https://Ajax.googleapis.com/Ajax/libs/Jquery/1.6.1/Jquery.min.js">
      </script>
      <script type="text/javascript" 
	src="https://Ajax.googleapis.com/Ajax/libs/Jqueryui/1.8.13/Jquery-ui.min.js">
      </script>
      <script type="text/javascript">
      $(document).ready(function() {
          setTimeout ( "try{pageReady();}catch(e){}", 0 );
          ......your other code......
       });
      ......your other code......
</script>
</HEAD>

Since our project was started from ASP.NET 1.1, we reference it in a pageHeader user control like the above. We reference it to Google site, then client won't bother our server to transfer the file even it is tiny. If you use Jquery, you should know $(document).ready function that will be called after all DOM objects were established in the page. We forward this call to page level, to call pageReady() that locates in our specify page and let it prepare data for each page. Due to this, pageReady() is optional and not every page needs it, so we put it in a try block.

Another point that we might pay attention to is the DOCTYPE in the page, it must be a new standard that supports xhtml to allow you use some Jquery function.
It might be other versions, but this works in my site.

HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Step 2: Build Ajax page (Jpage)

In this step, built the Ajax page (Jpage) without UI that allows other pages to inherit it. Its purpose is to load our Ajax function in the page and initialize the basic data for it, it also handles all the Ajax requests and invokes the method in your page by reflection.
This page is similar with Microsoft Ajax scriptManager. The code is shown below (read the common for statement purposes):

C#
using System;
using System.Text;
using System.Reflection;
using System.Web.Script.Serialization;
using System.Web;
namespace YourLogicNameSpace.YourDedefineName
{
    //declare restriction abstract allow pages to inherit only:
    public abstract class Jpage : System.Web.UI.Page
    {
        #region Variables
        //allow you serialize all data that will send client 
        //in page loading or Ajax response:
        protected static JavaScriptSerializer serializer = new JavaScriptSerializer();
        #endregion

        #region Web Form Designer generated code
        .........
        #endregion

        #region Properties
        //set property that reference your js path
        public string PathToJpageScript {
            get { return Page.ResolveUrl("YourPath/Jpage.js") + 
		"?version=" + Config.Version; }
        }
        #endregion

        #region Events
        //handle the client request before the page load.
        private void Page_PreLoad(object sender, System.EventArgs e) {
            HandleCallbacks();
        }

        //prepare the data for the javascript and load the js file.
        private void Page_Load(object sender, System.EventArgs e) {
            StringBuilder sb = new StringBuilder();
            sb.Append("var Jpage={};");
            //the text message will be displayed when session expired.
            sb.Append(string.Format("Jpage.msgExpired='{0}';", 
		Global.GetRes("Resources.Session.Expired")));
            //the path to login page when session expired.
            sb.Append(string.Format("Jpage.loginLink='{0}';", 
		this.Request.ApplicationPath + "/Login.aspx?ReturnUrl=" +
                                    Global.GetEscapedUrl(this.Request.RawUrl)));
            //it creates a javascript block to iniialize the variables 
            //from the page and load the js file.
            //the message and the link are prepared to handle session expiration.
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), 
			"Jpage_Block", sb.ToString(), true);
            Page.ClientScript.RegisterClientScriptInclude(this.GetType(), 
			"Jpage", PathToJpageScript);
        }
        #endregion

        #region Ajax Methods
        //handle the Ajax call from page
        protected void HandleCallbacks() {
            //whether it is Ajax call and get the invoke method name
            string callMethod = Request.Params["Ajax"];
            if (string.IsNullOrEmpty(callMethod))
                return;
            try {
                //use reflection to invoke method in page
                var result = this.GetType().GetMethod
			(callMethod, BindingFlags.NonPublic | 
			BindingFlags.Instance).Invoke(this, null);
                //serialize result and return to client
                AjaxResponse((result is string || result.GetType().IsValueType)?
				result.ToString():serializer.Serialize(result));
            } catch (Exception) {
                Response.StatusCode = 500;
                Response.Write("Server callback exception");
                Response.End();
            }
        }

        protected void AjaxResponse(string result) {
            Response.Clear();
            Response.ContentType = "application/json";
            Response.Write(result);
            Response.Flush();
            Response.End();
        }
        #endregion

        #region Helper Methods
        .....some utility methods that you want, like parse query string to parameter .....
        #endregion
    }
}

When we make an Ajax call by Jquery in the page, it passes the method name that we want to invoke in query string name [Ajax], then in HandleCallbacks methods, we check whether it is an Ajax call. If it is, we use reflection and try to invoke the method, the methods will return a result that could be a value type, string or object. If the result is object, we serialize the result to string as JSON format and call AjaxResponse() to return back to client.

Step 3: Build a Tiny JS File (Less than 1K)

For Ajax page to take care of Ajax request, response, error and session timeout, all Jpage properties are initialized in the C# script block.

JavaScript
//get the current page url.
var pgUrl=document.location.href;
//the login page regular expression pattern for session testing, 
//it depends on how you design.
var loginPattern=/<\s*html|HTML\s*>\s*<\s*head|HEAD\s*>.
*<\s*\/\s*head|HEAD\s*>\s*<\s*body|BODY\s*>.*<\s*form|FORM.* 
(YOUR LOGIN PAGE PATH .*>.*/m;

//attach the invoke method name to the url with timestamp to prevent cache
function AjaxPath(){return (pgUrl+((-1<pgUrl.indexOf('?'))?'&':'?')+
'Rand='+new Date().getTime()+'&Ajax=');}
//make Ajax call and handle response
function callAjax(funcName,Param,funcCallBack,fSync){
if(fSync){var V=null;}
$.AjaxSetup(
{error:function(xhr,status,err){handleAjaxError(xhr,status,err,funcName+' error.');},
type:'POST',
timeout:100000,
async:(!fSync||fSync==null)
});

$.getJSON(
AjaxPath()+funcName,
Param,
function(result,status,xhr){
if(result===false){testSession(JSON.stringify(xhr.responseText));}
if(fSync){V=result;}
else{window[funcCallBack](result);}
});
if(fSync){return V};
}

function handleAjaxError(xhr,status,err,errMsg){
if(xhr.readyState==0||xhr.status==0){return;} // this statement is for non-IE browsers, 
					// handle some fake errors.
else{alert(xhr.responseText+'; '+errMsg);}
}

//test response whether session timeout
function testSession(ResTxt){
try{
if(loginPattern.test(ResTxt.substring(0,10000))){
alert(Jpage.msgExpired);
window.location=Jpage.loginLink;
}
}catch(x){}
}

In the file, the callAjax() method fires Jquery Ajax call and handles the response, Ajax error and session timeout.

The function has 4 arguments, the function name that we want to call in the server, the parameter object that carries all the parameters, the callback function name that will handle the response from the server. The last one is the flag to allow you to call Ajax synchronize.

In the Jquery $.AjaxSetup:

handleAjaxError() function will display the error message from the server and also the invoke method name. To set the Ajax call type to 'POST' can make it accept big size query string and handle URL encoding.

async flag allows to make a synchronized Ajax call.

In the Jquery $.getJSON:

Initialize the Ajax URL as current page location and attach the method name that you want to invoke in server side, notice the "Rand=" in AjaxPath method, it uses current timestamp to prevent browser caching your call. When the Ajax call succeeds, first we check the result:

C#
if(result===false){testSession(JSON.stringify(xhr.responseText));}

In our project, if session is out, the server will redirect you to the login page. The content will be sent as responseText, but the result always is false, so it checks if result is false first, then test its text whether it is login page and redirect to login page in client side, otherwise it passes the result through to the next step.

After test session, it checks whether it is synchronize call, if yes, returns the result, otherwise calls the callback function by name passed with the result.

Step 4: Implement in the Page

First inherit the Jpage:

C#
public class Locations : Jpage {
......
}

Create the methods that you want to call in Ajax that are just like a normal method, but make sure these methods must be protected and have a return value. the reason why it needs to be protected is the reflection has restriction which set the flags "BindingFlags.NonPublic | BindingFlags.Instance" for the methods that it invokes, so that we can implement the encapsulation. Because we need to return the data to the client, it must have a return value. On the other hands, the return result can be different types. If it is string or valueType, it will be converted to string, otherwise, it will be serialized to JSON format as string to return.
In these methods, they will be invoked from Jpage HandleCallbacks() by reflection, sample shown below (I will discuss more details inside this code in the next part):

C#
#region Ajax methods
protected object getList() {
//Param() and ParamId() below are utility methods that parse 
//your parameter in query string from the Jquery Ajax call.
var result = YourLogicLayer.LookupLoation(Param("Company"), 
		Param("Loc"), Param("Zip"), Param("Phone"));

//logic layer return collection type result set and use LINC 
//to filter data that we need, convert it to light weight JSON format, 
//like [["ID","Name","Company".....],["195","mylocation","my company"...],
//[...another row information...],.....]
var list = result.OfType<YourLogicClass>().Select(i => new {
i.ID,
i.Name,
i.Company, Address=i.Address.FullAddressText
}).ToList().ToDataTable().ToJsonString();
return new { total = result.VirtualRows, list };
}
protected int delRow() {
return YourLogicLayer.Delete(Convert.ToInt32(ParamId("Id")));
}
#endregion

In the page JavaScript file, make the Ajax call by calling callAjax() which loaded in Jpage and pass method name in code behind, parameter and callback function name. If the return value is JSON format, you can directly access the result property to get what you want. The code is like this:

JavaScript
function tbResourceDelete(r){
if(confirmDelete(r)){
//make Ajax call, call method name 'delRow' in code behind, 
//pass parameters as object and call back function name 'tbResourceDeleteCallBack'
callAjax('delRow',{Id:r.find('td:eq('+tdIdx('IdCol')+')').html()},
	'tbResourceDeleteCallBack');
}
}

function tbResourceDeleteCallBack(result){
if(1==result){goPage(currentPg);}
else{alert('delete failure.')}
}

In the next part, I will demo an Ajax datagrid user control using Jquery and JSON format and this Jpage function.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)