Click here to Skip to main content
15,884,064 members
Articles / Web Development / ASP.NET

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

Rate me:
Please Sign up or sign in to vote.
4.69/5 (8 votes)
15 Sep 2011CPOL6 min read 33.2K   599   32   8
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.

JavaScript
<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.NET
<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.NET
<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.

SQL
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.

C#
[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.

C#
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.

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:

JavaScript
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:

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

History

  • 16th September, 2011: Initial post

License

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


Written By
Architect Pramerica Systems Ireland
India India
CORE COMPETENCIES

 Design and Architecture for Microsoft SOA implementations using BizTalk, WCF, WF, SQL Server Integration Services & ESB Toolkit.

 Web Application design and implementation using ASP.NET MVC with jQuery & Entity Framework with LINQ for persistence layer.

 Designing and developing desktop applications using WPF, WinForms.

 SQL Server Database design & programming

EXPERIENCE SUMMARY

 Eleven years total, out of which 04 years as architect, 07 years as designer and developer in various Microsoft technologies like WinForms, ASP.NET WebForms, ASP.NET MVC, BizTalk, WCF, WF, WPF, SQL Server, LINQ, EF etc. Worked in various roles mainly architect, designer, team leader and developer.

 Hands on experience with ASP.NET web applications (both MVC and Web Forms) and desktop based applications as well as smart client applications using latest technologies harnessing .NET Framework 4.0, C# 4.0, ASP.NET 4.0, WCF, WF, WPF and LINQ.

 Hands-on working experience in Application integration, business process management and service oriented applications using BizTalk Server 2010, ESB Toolkit 2.1, WCF 4.0 services and SQL Server 2008 Integration Services.

 Thorough working knowledge of OOAD and agile / incremental development process.

 Experience in leading team of developers for on schedule project delivery with quality.

 Experience with low level programming like embedded C, C++ as well as systems programming on unix platform.
REMARKABLE PROFESSIONAL ACHIEVEMENTS

 Got Microsoft Community Contributor Award in year 2011 with MCC ID# 4034514.

 Published article in MSDN Magazine Feb 2011 edition on MDM with F#: http://msdn.microsoft.com/en-us/magazine/gg598923.aspx
http://www.codeproject.com/News/14767/Pattern-Matching-Database-Records-with-Fsharp.aspx

 Published highly popular article on BizTalk in www.dotnetcurry.com
http://www.dotnetcurry.com/ShowArticle.aspx?ID=683

 Umpteen blogs in BizTalk server forums and ESB toolkit forums.

Comments and Discussions

 
QuestionHow to perform CURD operations on database using WCFREST service&also consume this service in ASP.NET Webpage perform CRUD operationd Pin
Member 917112816-Jul-12 23:59
Member 917112816-Jul-12 23:59 
QuestionNo security? Pin
T M Gray20-Sep-11 9:32
T M Gray20-Sep-11 9:32 
When you eliminate postbacks you also eliminate a lot of the built-in security features of ASP.Net. Exposing your underlying CRUD methods directly to the client makes it much more succeptible to brute force attacks. Anyone considering this methodology really needs to consider the security implications.
AnswerRe: No security? Pin
AmbarRay21-Sep-11 19:24
professionalAmbarRay21-Sep-11 19:24 
GeneralRe: No security? Pin
MrAnderson1st7-Oct-11 5:22
MrAnderson1st7-Oct-11 5:22 
QuestionGreat stuff Pin
smoore419-Sep-11 22:23
smoore419-Sep-11 22:23 
QuestionUpdate Pin
martin.nedopil15-Sep-11 23:28
martin.nedopil15-Sep-11 23:28 
AnswerRe: Update Pin
AmbarRay18-Sep-11 20:03
professionalAmbarRay18-Sep-11 20:03 
AnswerRe: Update Pin
AmbarRay10-Oct-11 1:00
professionalAmbarRay10-Oct-11 1:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.