Thursday 29 December 2011

Update On Long Running Server Tasks using ASP.Net, jQuery and Ajax.

          Often in distributed applications, There is a need to update the client on a long running server task. This becomes inherently difficult because of the ‘statelessness’ of the HTTP protocol, In that, Between every HTTP Get there is no state maintained on the server (well at-least in most cases). Therefore, when a client request starts and owns a process which is lengthy (often like uploading something, or communicating to/from a remote database server etc..), periodic updates on the progress of the lengthy process is very imperative for a good user experience, specially in the web 2.0 generation.

I’m going to discuss a few techniques to achieve this using an ASP.Net Ajax development model considering a Windows Server scenario here. Following are the most commonly used techniques for achieving it.

  • Server Push
  • Client Pooling

Server Push (COMET)

In very simple words, COMET is a technique/web application model where the server keeps the HTTP connection open for longer durations. This allows the server to push updates to the client. This can be achieved using techniques like HTTP Streaming, Hidden iFrame and XMLHttpRequests (AJAX) to name a few.

  • Advantages
    1. Saves Traffic –  The server needs to make just one call to the client to send an update.
    2. Efficient – From a logical architecture point of view of the application, it is a very simple and efficient way of updating the client. (This might come at a cost, see below). A very good example of COMET technique is the meebo messenger service. (check it out here) You can also check out the Google implementation here (Etherpad). This was used in Google Wave.
    3. Although a little tricky to achieve this using native ASP.Net architecture, You can leverage  HTML 5 Web Sockets to achieve it. A C# Implementation - Nugget is available on codeplex.
    4. Can be ideal for real-time or close to real-time update scenarios.
  • Drawbacks
    1. Server Memory – The more state that you would want to maintain on the server, the more server memory is required. This again, depends on a lot of factors. For instance, consider applications like Hotmail and Gmail, Here, the number of concurrent connections open can be  significantly higher, which means a lot of server state should be maintained, which will eventually require significant memory. On the other hand, if you are writing an ASP.Net Web App running on a intranet, your concurrent connections may be a couple of tens of them., which also means less server memory compared to the above scenario.
    2. Server I/O API -  This process itself depends on what I/O API is leveraged on the server. Asynchronous processes generally use Non-Blocking I/O, utilizing all cores on the server and increasing efficiency. Async process are handled by a separate thread, which also means the application can do something else while this Async thread executes. Blocking I/O requires a thread per connection and as the concurrent connections increase, the no. of threads processing that request will also increase. A good debate on Non-Blocking vs. Blocking I/O can be found here.
    3. COMET style model implementations have a tendency to run into difficulties as the application is scaled up for large user bases, simply because the server needs to maintain multiple connections between the same client and server. (This is not a claim, I will be supporting all these explanations with concrete implementations and load tests soon.)

Client Polling

Client Polling is done from the browser through AJAX requests. The browser repeatedly polls the server for updates through Ajax calls and updates the client from the server’s response.

  • Advantages
    1. Simple to implement
    2. Suitable for non-real-time applications (like chat-clients)
  • Drawbacks
    1. Latency -  There can be latency between the client’s poll and the server’s response. See the below scenarios. This is mainly due to the unpredictable progress of the server’s process and the constant time interval of the poll.
    2. Not efficient use of traffic and resources – Not every poll to the server might get a concrete response. Don’t get me wrong here, I’m not trying to say that not every pool might get a response, but between two consecutive polls, the state of the long process on the server would not have changed, forcing the server to repeat the previous response. i.e let’s say the the client polls the server every 20 milliseconds for an update, Now, the server might return a different value only after 100 milliseconds, by which time you can imagine the client would have polled the server 4 times already rendering the previous 4 calls to the server without result. This is not efficient use of traffic and reduces your application efficiency. There can be another scenario here, Consider the server’s process returns a state change response every 10 milliseconds. Now, if the client polls the server at intervals of 20 milliseconds, the server’s process has changed significantly since then, adding to a loss of update between every poll.

Both COMET and Client Polling have their ups and downs. As you’ve seen, there strictly isn’t a stereotypical way of achieving the end result, The most imperative of these points are that when it comes to what’s best to YOU, you might have to think on the above lines, scoping out various factors of your distributed application and then your choice will be obvious.

Below is my implementation of a client AJAX Polling to server for a update on the long running server process.

Example : Visual Studio 2010, Asp.NET 4.0, jQuery 1.7, jQuery UI 1.8

I’ve written a very simple AJAX client pooling demo here. The server starts a ‘BackgroundWorker’ process Asynchronously and the client polls the server at regular intervals by making AJAX calls and getting the updates on the server progress. I’ve used jQuery UI to draw a progress bar and update it asynchronously after every poll response from the server. I’ve used jQuery in the client to make use of $.ajax({}); call and the server response is a JSON data type. This is a demo implementation only. Here, the BackgroundWorker object is made static. Therefore this implementation sends the progress of the same job to all the client requests which are polling for an update. An enterprise application would need to have a separate web service running on the server to do the ‘long task’ and each request will then need to be INDEPENDENTLY made aware of it’s Async process’s progress.

Default.aspx.cs

  1: using System;
  2: using System.ComponentModel;
  3: using System.Threading;
  4: using System.Web.Services;
  5: 
  6: namespace ClientPoolServerProgress
  7: {
  8:     public partial class _Default : System.Web.UI.Page
  9:     {
 10:         static BackgroundWorker bwProcess; 
 11:         public static int Percentage { get; set; }
 12: 
 13:         protected void Page_Load(object sender, EventArgs e)
 14:         {
 15:             Percentage = 0;
 16:         }
 17: 
 18:         [WebMethod()]
 19:         public static int GetProgress()
 20:         {
 21:             return Percentage;
 22:         }
 23: 
 24:         protected void btnClick_Click(object sender, EventArgs e)
 25:         {
 26:             bwProcess = new BackgroundWorker
 27:             {
 28:                 WorkerReportsProgress = true,
 29:                 WorkerSupportsCancellation = true
 30:             };
 31: 
 32:             bwProcess.DoWork += new DoWorkEventHandler(bwProcess_DoWork);
 33:             bwProcess.ProgressChanged += new ProgressChangedEventHandler(bwProcess_ProgressChanged);
 34:             bwProcess.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwProcess_RunWorkerCompleted);
 35: 
 36:             bwProcess.RunWorkerAsync("AsyncWorker");
 37:         }
 38:         
 39:         void bwProcess_DoWork(object sender, DoWorkEventArgs e)
 40:         {  
 41:             for (int i = 0; i <= 100; i++)
 42:             {
 43:                 if (bwProcess.CancellationPending) 
 44:                 { 
 45:                     e.Cancel = true; 
 46:                     return;
 47:                 }
 48:                 bwProcess.ReportProgress(i);
 49:                 Thread.Sleep(20);
 50:             }
 51: 
 52:             e.Result = "100 %";
 53:         }
 54: 
 55:         void bwProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
 56:         {
 57:             Percentage = e.ProgressPercentage;
 58:         }
 59: 
 60:         void bwProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
 61:         {
 62: 
 63:         }
 64:     }
 65: }
 66: 


Default.aspx



  1: <%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="false"
  2:     CodeBehind="Default.aspx.cs" Inherits="ClientPoolServerProgress._Default" 
  3:     Async="true" Buffer="True" EnableSessionState="ReadOnly" AsyncTimeout="300"%>
  4: 
  5: <asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
  6:     <script type="text/javascript">
  7: 
  8:         $(document).ready(function () {
  9:             updateProgress();
 10:             $("#pBar").progressbar({ value: 0 });
 11:         });
 12: 
 13:         function updateProgress() {
 14:             $.ajax({
 15:                 type: "POST",
 16:                 url: "Default.aspx/GetProgress",
 17:                 data: "{}",
 18:                 contentType: "application/json; charset=utf-8",
 19:                 dataType: "json",
 20:                 async: true,
 21:                 success: function (msg) {
 22:                     $("#lblProgress").text(msg.d);
 23:                     $("#pBar").progressbar({ value: msg.d });
 24: 
 25:                     if (msg.d < 100) {
 26:                         setTimeout(updateProgress, 10);
 27:                     }
 28:                 },
 29:                 cache:false 
 30:             });
 31:         }
 32:     </script>
 33: </asp:Content>
 34: <asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
 35:     <div>
 36: 
 37:      <asp:UpdatePanel ID="updPanel" UpdateMode="Always" runat="server" >
 38:         <ContentTemplate>
 39:             <table class="ui-widget ui-widget-content" width="400">
 40:                 <tr>
 41:                     <th class="ui-widget-header" style="width:150px;" >
 42:                         Item
 43:                     </th>
 44:                     <th class="ui-widget-header">
 45:                         Details
 46:                     </th>
 47:                 </tr>
 48:                 <tr>
 49:                     <td>
 50:                         Percent Progress
 51:                     </td>
 52:                     <td>
 53:                         <label id="lblProgress"> </label> 
 54:                     </td>
 55:                 </tr>
 56:                 <tr>    
 57:                     <td>
 58:                         Progress Indicator
 59:                     </td>
 60:                     <td>
 61:                         <div id="pBar"></div>
 62:                     </td>
 63:                 </tr>
 64:     
 65:                 <tr>
 66:                     <td colspan="2">
 67:                             <asp:button ID="btnClick" runat="server" Text="Start" CssClass="ui-button" 
 68:                              onclick="btnClick_Click" />
 69:                     </td>
 70:                 </tr>
 71:             </table> 
 72:           </ContentTemplate>
 73:     </asp:UpdatePanel>
 74:     </div>
 75: </asp:Content>
 76: 


Capture



Download Code (C#)


Tuesday 27 September 2011

Sudhir Murthy is back!

It's been a while since i've blogged now.

I am intending to make a come back with lots of rablings on Technology particularly ASP.Net, MVC, Ajax, jQuery, Web Application Architecture, Application Security, Azure, App Fabric, SQL Server, Disaster Recovery and Data Contigency Planning with SQL Server 2008, Parallel Processing, .Net BCL, F#, Windows 8 , HTML5, Software testing with Visual Studio, MSF Agile and Scrum with TFS, Music and everthing that i've been upto for some time now.. Watch this space..

Thursday 5 May 2011

Shale Gas - An alternative to Renewable ?

Shale Gas is natural gas produced from shale.(a type of rock). Analysts predict that Shale Gas has the potential to greatly expand worldwide energy supply.

There are ongoing debates on turning to Shale gas production over Renewable Energy (green). I found an interesting read on the guardian here. Also, Some facts and figures on shale gas.

Royal wedding preparations

Was driving in London..This is London getting ready for the royal wedding the previous day.



Android Tablets - A Comparison



As the surge of the android tablets begin this year, I guess more and more people will be looking into
buying an android tablet over the iPad. Found this interesting comparison chart of  The Motorola Xoom, The Samsung Galasy Tab 10.1, The Asus Eee Pad Transformer , the LG G-Slate (Optimus Pad) and the Acer Iconia A500.

Monday 2 May 2011

Bonjour, voila, merci..

France was a very good experience. I had never tried to speak French before and this time it was inevitable in France. The French do get delighted when non-native looking , non-native sounding and non-native smelling people like me try to speak French. I get the feeling that they are deeply rooted to their culture and they appreciate it when non-native people attempt to converse in French.

France was a spectacular experience. The sheer sight of Eiffel tower, The palace and gardens in Versailles, The magnificent Louvre museum, notre dam, hotel les des invades, arc de triumph, the opera, the cabre show, the hop on -off tour buses , the strange and funny smell of sewage in Paris, The metro, The French tourism dept, The bridges in Paris, people staring at passerbys from roadside restaurante, no. of people smoking on the streets of Paris, the funny French Hindu converts dancing on the streets singing hare Rama, ridiculous ripoff taxis with meters which seem to be running time based as against distance based,restaurante indiens, wine, champagne, more bridges, pick pockets on streets, free public transport, French people giving directions in french,the designer wears of armaani, milan, ck and the likes, 1 euro Eiffel tower selling boys calling out sasriakaal , rich shoppers on camps-elysees, the tabac shops, the distinctive English accent of the French,confusing traffic direction on roads because of left hand driving, spectacular night tour of Paris, superb nightlife, very Indian looking roads with a lot of animated people, vegetariane paninis..phenomenal French buildings and monuments which speak of the historical France and not to mention the great French revolution..endless memories, sweet memories..


Wednesday 27 April 2011

Blogger for Android

Finally!!!, was anticipating this for a while now.(May be 6 months..) I'm glad it has come to android. Makes me wonder why it took so long for Google to get this simple app on  android market. Whatever the reasons might be , I'm glad its out on the market.

Nothing can stop me from penning down my thoughts now..!!

Angaraag Papon Mahanta!!

 

 

Brilliant Singer!! Unbelievable Voice. It has been blowing away my mind off-late

ASP.NET and HTML5 Local Storage

 

HTML5 Local Storage and consuming it through ASP.NET. A great read.

With this entry on my blog, I’m making a comeback into my writing world. I had remained silent for quite a while now. Sometimes life just takes over.  Reasons can be innumerable. Right!, After battling it out with life, i’m glad, i’ve finally made time to post things on my blog again.