Showing posts with label ASP.Net. Show all posts
Showing posts with label ASP.Net. Show all posts

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#)


Wednesday 27 April 2011

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.

Tuesday 7 September 2010

Entity Framework 4.0 and ASP.Net 4.0

This is a very good example of real world EF and ASP.Net .
Published with Blogger-droid v1.5.8

Sunday 28 February 2010

Handling ASP.NET ‘Thread Aborted Exception’

If you would have bumped into ‘Thread Aborted Exception’ in ASP.NET apps when trying to do a lengthy server process, They would have been interesting times fore sure.

Well, Firstly ,  The ‘Thread Aborted Exception’ happens when the thread serving the request doesn't
finish for a long time. The ASP.NET hosting process aborts this thread after a certain time which can be adjusted in the ‘executionTimeout’ attribute of the ‘httpRuntime’ element in the  ‘Web.Config’ file.

<system.web>
    <httpRuntime executionTimeout="600" />
  </system.web>
By default the executionTimeout="90" seconds.

 

Although this might solve the problem , this is not a feasible solution primarily because of scalability reasons, i.e increasing the executionTimeout might decrease the throughput of your web app.

 

I did an interesting workaround this to ‘ping’ the server at intervals just short of the ‘executingTimeout’ parameter. Now, the idea is, if a process/function/routine takes enormous amount of time (which happens to raise the Thread Aborted Exception) to complete because it’s massive., break the process/function/routine into smaller chunks and ping the server at regular intervals. This can be achieved by storing the execution states in a session variable on the server.

 

Further, this will open up an opportunity to monitor the progress of your process. Say you’ve re-factored the lengthy routine which was a single function  to 10 functions. Every time you finish a function, you can update your progress on the client and continue with the next function on the server.

Advantages

1] This will avoid the ‘Thread Aborted Exception’ and

2] Progress can be monitored.

Disadvantages

1] There is an argument that any lengthy processes must not be done on the asp.net thread pool thread and that such processes should be written as a separate windows service. Well, at the end of the day it depends on your business needs. Personally, i feel you need to consider things like will the app be running on business lan or exposed to the internet , how many simultaneous users will it have ?. Will it be running on a cluster or a single server etc..

Saturday 13 February 2010

Trick for creating a ‘notification’ screen without AJAX – ASP.Net 1.1

If you are developing on ASP.Net 1.1, the first thing which makes you lose the will to live (especially, if you’re accustomed to ASP.Net Ajax) is obviously the missing AJAX framework!

There is very little you could do with ASP.Net Forms for example, displaying a notification screen when you are processing something in the background after a post pack.

Without using jQuery , Javascript XMLHttp Requests or an open source AJAX framework for ASP.Net 1.1 your probably stumped , so was i., until i found out a trick to do something similar but with a post back (oh, what the heck!, but it still works, given the fact that i can display a notification screen before i start a lengthy process on the server.)

The Trick.

0] Create a session object , let it be an instance of a class which has some properties than can be set.

1] In the Form_Load hander, invoke your lengthy process depending on a Boolean property in your session object.

3] On the dreadful postback, when you want to start the ‘lengthy process’, Set your session object’s Boolean property and do a Response.Redirect(“yourwaitingscreen.aspx”). This will show the waiting screen immediately, however you have still not started the lengthy process.

4] Finally, starting the lengthy process is easy.

Add this in your <meta> tag to “yourwaitingscreen.aspx” to do the magic.

<meta http-equiv=”refresh”; content=1 url=”your_lengthy_process_aspx_page.aspx”>

I can hear the Gotchas !!! and ahas!!! now.

The way asp.net processes the request is still synchronous., remember no AJAX either. But, we are taking advantage of the synchronous processing itself. i.e when we add the

‘<meta http-equiv=”refresh”; content=1 url=”your_lengthy_process_aspx_page.aspx”>’ line to

“yourwaitingscreen.aspx”, you are loading the page, which starts the ‘lengthy process’, but since you are already in the ‘waiting screen’, you need not do anything. you also get a progress bar with IE and Firefox etc. (bonus!!!)

Drawbacks:- postbacks and logic in your Form_Load to start the ‘lengthy process’ (can be accomplished using a session variable as discussed above)

But, that’s fairly trivial given the fact that you are telling the user that you are doing something in the background which is going to take some time. (as simple as that.) – with a progress bar inherently displayed by the browser.

Advantages

It’s maintainable because the ‘lengthy process’ can be loosely coupled with your UI or service. You can re-factor/enhance/test your code for ‘lengthy process’ in isolation, which makes it scalable and may be reusable!

Tuesday 10 June 2008

Discovering Patterns in .Net BCL and ASP.Net

Patterns behind the scenes in .Net and ASP.Net

I just found this great article on MSDN which enlightens the .Net programmer about the patterns used in .Net BCL and ASP.Net. The link to this great article can be found here.