Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Achieving Zero Postback Business Sites Leveraging jQuery and ASP.NET Web Services

0.00/5 (No votes)
15 Sep 2011 1  
This article elaborates how to accomplish a zero postback site using jQuery and ASP.NET web services

Introduction

This article explains how to write business websites with zero postback (no partial / full postback or in other words no form submit), harnessing jQuery and ASP.NET web services. This article also shows how to call a web service with a .NET object as parameter, from client side jQuery code and how to manipulate on the received object returned as a result of web service call.

Background

Let's go back to the basics. Why do we have controls? The reason is that if we don't have it, we would have to print textual information plainly and it would be very difficult for users to work interactively with web sites. The whole story of form submit (postback) began from there. How does the server know that some user interaction has happened and it needs to do something? Answer is postback. Postbacks became very annoying soon and it gave way to AJAX technology enabling asynchronous partial postbacks where only the controls in a particular update panel would be postback to the server, of course, alongwith the associate irritating baggage of ViewState. For such postbacks too, the update panel again goes through almost all events like Page_Init, Page_Load, Control Events, Page_PreRender, etc. except however, the Page_Render. Soon, even this became annoyingly slow at times when there is heavy load on bandwidth. So what if there is absolutely no form submit or no partial postback. There should be a mechanism to allow users to interact with the controls in the client side (which is well known and easy too) and then have the server respond to such interactions happening at the browser level (which I would address now). We know that client side script can call ASP.NET web services which are decorated with [ScriptService] attribute. So, if somehow we could put the state of the pertinent controls in an object and call such a service from jQuery (client side) and then obtain another object as a return value from the aforesaid service and subsequently change the state of controls at the client side, then our job is done. Users now know that depending on his / her interaction server has responded and the site has reflected that accordingly. So if this is what is required, then why do we need postback at all.

Using the Code

The code is nothing but a solution containing a simple ASP.NET web site having a master page and just one extra web content form just to illustrate the concepts. Only three server controls are used, one asp:Button, one asp:Label and one asp:DropDownList.

We must first add the .js files jquery-1.4.1.js and JSON2.js. JSON2.js has been downloaded from http://www.JSON.org/json2.js. It contains the much useful JSON.stringify() function which JSON serializes a JavaScript object such that it could be sent as a parameter to the web service call which accepts an analogous .NET object as a parameter. We should first include the references to the .js files in our master page between <head> .... </head> section.

<script type="text/javascript" src="jquery-1.4.1.js"></script>
<script type="text/javascript" src="JSON2.js"></script>
<script type="text/javascript" language="javascript">
window.history.forward(1);
</script>

In the above code, we include references to the .js files and disable the back button of browser site wide. We also include a ScriptManager within the <form> .... </form> tag:

<asp:ScriptManager ID="KovairScriptManager" runat="server" 
EnableScriptGlobalization="true" 
EnablePageMethods="true"> </asp:ScriptManager>

Now, we go to our web content form Default.aspx.

Let's declare the controls now:

<asp:Button ID="btnRetrieveData" runat="server" 
Text="GetData" Width="175px" 
OnClientClick = "javascript:return GetStudents();" UseSubmitBehavior="false"/>

<asp:DropDownList ID="ddlStudents" runat="server" 
Height="16px" style="width: 77px" 
Width="250px"></asp:DropDownList> 

<asp:Label ID="lblResult" runat="server" 
Text="Label" Height="50px" Width="100px">
</asp:Label>

Now let us create two tables in database Student.

USE
[Student] 
GO
CREATE TABLE [dbo].[StuRec]( 
[RollNo] [int] IDENTITY(1,1) NOT NULL, 
[Name] [nvarchar](50) NULL, 
CONSTRAINT [PK_StuRec] PRIMARY KEY CLUSTERED ([RollNo] ASC )
GO
CREATE TABLE [dbo].[StuMark]( 
[RollNo] [int] NOT NULL, 
[Marks] [int] NULL, 
CONSTRAINT [PK_StuMark] PRIMARY KEY CLUSTERED ([RollNo] ASC)
GO
ALTER TABLE [dbo].[StuMark] WITH CHECK 
ADD CONSTRAINT [FK_StuMark_StuRec] 
FOREIGN KEY([RollNo]) REFERENCES [dbo].[StuRec] ([RollNo]) 
GO

We add two tables StuRec containing RollNo and Name of student and StuMark, containing RollNo and Marks of the student being referred. This has been done just to explain the concept that from the client side if a student is selected in dropdownlist, then his / her corresponding marks should be displayed in a label by bringing in the appropriate record from the StuMark table. Fill the tables with appropriate data.

So now, we first write the web services, one to get all students from StuRec table and another one to get a particular student's marks from StuMark table. Take note that the web service class has been decorated with [ScriptService] attribute so that it could be called from client-side script.

[WebService(Namespace = "http://localhost/Kovair.Site")]
[ScriptService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class KovairWebService : System.Web.Services.WebService {
public KovairWebService () 
{
}

[WebMethod]
public List<ListItem> GetStudents() {
string connStr = 
ConfigurationManager.ConnectionStrings["KovairSiteConnectionString"].ToString();
SqlConnection conn = new SqlConnection(connStr);
SqlCommand comm = new SqlCommand();
comm.CommandText = "SELECT RollNo, Name From dbo.StuRec";
comm.Connection = conn;
SqlDataAdapter da = new SqlDataAdapter(comm);
DataSet ds = new DataSet();
conn.Open();
da.Fill(ds, "StudentRecord");
conn.Close();
List<ListItem> stuList = new List<ListItem>();
if (ds.Tables != null)
{
    int recordCount = ds.Tables["StudentRecord"].Rows.Count;
    if (recordCount > 0)
    {
        DataTable dtab = ds.Tables["StudentRecord"];
        for (int i = 0; i < recordCount; i++)
        {
            stuList.Add(new ListItem(
            dtab.Rows[i]["Name"].ToString(),
            dtab.Rows[i]["RollNo"].ToString()
            ));
        }
     }
   }
return stuList;
}
[WebMethod]
public StuMark GetStudentDetail(StuRec stu)
{
string connStr = 
ConfigurationManager.ConnectionStrings["KovairSiteConnectionString"].ToString();
SqlConnection conn = new SqlConnection(connStr);
int roll = stu.RollNo;
SqlCommand comm = new SqlCommand();
comm.CommandText = 
@"SELECT R.RollNo, M.Marks From dbo.StuMark M INNER JOIN 
dbo.StuRec R ON M.RollNo = R.RollNo WHERE R.RollNo = @rollNo";
comm.Parameters.Add(new SqlParameter("@rollNo", SqlDbType.Int)).Value = roll;
comm.Connection = conn;
SqlDataAdapter da = new SqlDataAdapter(comm);
DataSet ds = new DataSet();
conn.Open();
da.Fill(ds, "StudentDetailRecord");
conn.Close();
string marks = String.Empty;
if (ds.Tables != null)
{
    int recordCount = ds.Tables["StudentDetailRecord"].Rows.Count;
    if (recordCount > 0)
    {
       DataTable dtab = ds.Tables["StudentDetailRecord"];
       marks = dtab.Rows[0]["Marks"].ToString();
     }
}
StuMark sm = new StuMark();
sm.RollNo = stu.RollNo;
sm.Marks = Convert.ToInt32(marks);
return sm;
}
}

In the second web service, we have a parameter stu of type StuRec and it returns an object of type StuMark. The object definitions are shown below. They are .NET objects.

public class StuMark
{
public int RollNo { get; set; }
public int Marks { get; set; }
}
public class StuRec
{
public int RollNo { get; set; }
public string Name { get; set; }
}

Now, we shall see how we call the first web method GetStudents() which returns a List object of type ListItem. Why we are returning List<ListItem>? Because we want to add these ListItems to the DropdownList in the client side. The JavaScript method GetStudents() should be called if the button is clicked because it is tied up with OnClientClick attribute of the button. We leverage the jQuery utility $.ajax() to call a web service using jQuery from client side. The code is terse, clean and readable. Hence people find jQuery better than JavaScript.

function GetStudents() {
$('#<%=ddlStudents.ClientID %>').empty().append
('<option selected="selected" value="0">Loading...</option>');
$.ajax({
type: 'POST',
url: 'http://localhost/Kovair.Site/KovairWebService.asmx/GetStudents',
data: {},
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(response, status) {
var list = (typeof response.d) == 'string' ? eval('(' + response.d + ')') : response.d;
var control = $('#<%=ddlStudents.ClientID %>');
control.removeAttr("disabled");
control.empty().append('<option selected="selected" value="0">Please select</option>');
$.each(list, function() {
control.append('<option value ="' + this['Value'] + 
'">"' + this['Text'] + '"</option>');
});
},
failure: function(response) {
alert(response.d);
}
}
);
}

jQuery works with JSON. Hence we see that the content type is JSON and data type is JSON. The URL is of the form web service URI / web method. On success, we collect the List<ListItem> returned and run a $.each() jQuery function to iterate through the same and add them to the dropdownlist in the client side. So no form submit, no postback.

But the real fun lies in the second web method which has a parameter stu of type StuRec which is a .NET object. Now how does jQuery pass a parameter which is a .NET object? The answer is JSON and JavaScript object. We create a similar JavaScript object and convert it to appropriate JSON string with the help of JSON.stringify() function written in JSON2.js. The code is shown below:

var NewStudent = {};
NewStudent.RollNo = 22;
NewStudent.Name = "Jacob";
// Create a data transfer object (DTO) with the proper structure.
var DTO = { 'stu': NewStudent };
  
$(function() {
   $('#<%=ddlStudents.ClientID %>').change(function(e) {
        var rollNo = this.options[this.selectedIndex].value;
        var name = this.options[this.selectedIndex].text;
        NewStudent.RollNo = rollNo;
        NewStudent.Name = name;
        $.ajax({
             type: 'POST',
             url: 'http://localhost/Kovair.Site/KovairWebService.asmx/GetStudentDetail',
             data: JSON.stringify(DTO),
             contentType: 'application/json; charset=utf-8',
             dataType: 'json',
             success: function(response, status) {
   var list = (typeof response.d) == 'string' ? eval('(' + response.d + ')') : response.d;
       var oup = "RollNo: " + list.RollNo.toString() + " Marks: " + list.Marks.toString();
       $('#<%=lblResult.ClientID %>').html(oup);
      },
      failure: function(response) {
      alert(response.d);
      }
    }
   );
  }
 )
}
);

In the above method, we use short notation of $document.ready() which could be $.ready() or simply $(). We register the change event of dropdownlist during initial form load where we specify what is to be done if the selection of the dropdownlist changes anytime after the page is initially loaded. Prior to that, we create an object NewStudent in JavaScript which collects the values of the selected value and selected text and that is JSON-text converted using JSON.stringify in order to be passed as a parameter to web service. On success, the field values of the returned object is collected in a JavaScript object variable again and then displayed in a label.

Points of Interest

We have learnt how to call a web service attributed with [ScriptService] attribute from jQuery using $.ajax() call as a response to a control event trapped at the client side (browser). Thus we have learnt how to fetch data and display the same in the client side without submitting the form at all as is evident from the code behind file for default.aspx which is just having the code behind class declaration as shown below:

public partial class _Default : System.Web.UI.Page
{
}

History

  • 16th September, 2011: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here