Geeks With Blogs
Amit's Blog Sharing Thoughts and Learning

If you ever try to do more than one simultaneous partial update with Asp.net Ajax Update Panel, I guess  you already found  that Asp.net Ajax Framework cancel the current update request and starts the new one. You think I am kidding? Okay lets try the following code:

<%@ Page Language="C#"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            lblDate1.Text = lblDate2.Text = DateTime.Now.ToString();
        }
    }

    protected void btnDate1_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(1000 * 5); // Sleeps 5 second
        lblDate1.Text = DateTime.Now.ToString();
    }

    protected void btnDate2_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(1000 * 5); // Sleeps 5 second
        lblDate2.Text = DateTime.Now.ToString();
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Update Panel</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="updDate1" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                Update Panel 1: <asp:Label ID="lblDate1" runat="server"></asp:Label>
                <asp:Button ID="btnDate1" runat="server" Text="Update Time" OnClick="btnDate1_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
        <div>
            <asp:UpdatePanel ID="updDate2" runat="server" UpdateMode="Conditional" RenderMode="Inline">
                <ContentTemplate>
                    Update Panel 2: <asp:Label ID="lblDate2" runat="server"></asp:Label>
                    <asp:Button ID="btnDate2" runat="server" Text="Update Time" OnClick="btnDate2_Click" />
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
    </form>
</body>
</html>

The example is quite simple, I have two update panel which UpdateMode is set to Conditional, upon clicking the buttons inside the update panel I am doing a fake delay of 5 seconds then printing the current time of the server in the labels. Okay now run the code and click the first button and then click the second button in 5 seconds so that you can do simultaneous update. What happens, the first label never gets updated? Yes this is the nature of update panel, it cancels the current call and start executing the new one. You can get a more clear picture if you run it in FireFox with FireBug, Open FireFox Click Tools->FireBug->Open FireBug, then move to the Console tab in the firebug and repeat the button clicks, you will find only the last request spinning  animation gets completed.

I can understand the Update Panel does a monsters job for us, executing the full life cycle of the page in the server, generating the updated part of the page, downloading new scripts, updating viewstates etc and that is why it needs to work serially. But how come it discards it current update request once it found a new request? is not it better if it queues the new request and execute it once the current request completes?

Now Consider the following page:

<%@ Page Language="C#"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            lblDate1.Text = lblDate2.Text = DateTime.Now.ToString();
        }
    }

    protected void btnDate1_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(1000 * 5); // Sleeps 5 second
        lblDate1.Text = DateTime.Now.ToString();
    }

    protected void btnDate2_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(1000 * 5); // Sleeps 5 second
        lblDate2.Text = DateTime.Now.ToString();
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Update Panel Enhanced</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
            <Scripts>
                <asp:ScriptReference Path="~/Test/PageRequestManagerEx.js" />
            </Scripts>
        </asp:ScriptManager>
        <script type="text/javascript">
            PageRequestManagerEx.init();
        </script>
        <asp:UpdatePanel ID="updDate1" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                Update Panel 1: <asp:Label ID="lblDate1" runat="server"></asp:Label>
                <asp:Button ID="btnDate1" runat="server" Text="Update Time" OnClick="btnDate1_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
        <div>
            <asp:UpdatePanel ID="updDate2" runat="server" UpdateMode="Conditional" RenderMode="Inline">
                <ContentTemplate>
                    Update Panel 2: <asp:Label ID="lblDate2" runat="server"></asp:Label>
                    <asp:Button ID="btnDate2" runat="server" Text="Update Time" OnClick="btnDate2_Click" />
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
    </form>
</body>
</html>

The only difference you will find from the previous one that I have added a new JavaScript file PageRequestManagerEx.js and called a method PageRequestManagerEx.init(). Now run this page and repeat the button clicks, you will find the complete source in the bottom of this post. If you run it in FireFox with FireBug, you will find that no matter how many clicks you made in those buttons there is only one concurrent call and once the current call completes it executes another call. Yes as you have guessed the new JavaScript file which I just added does the trick. Now let us see what is in the JavaScript file.

var PageRequestManagerEx =
{
    _initialized : false,

    init : function()
    {
        if (!PageRequestManagerEx._initialized)
        {
            var _callQueue = new Array();
            var _executingElement = null;
            var prm = Sys.WebForms.PageRequestManager.getInstance();

            _prm.add_initializeRequest(initializeRequest);
            _prm.add_endRequest(endRequest);

            PageRequestManagerEx._initialized = true;
        }

        function initializeRequest(sender, args)
        {
            if (_prm.get_isInAsyncPostBack())
            {
                //if we are here that means there already a call pending.

                //Get the element which cause the postback
                var postBackElement = args.get_postBackElement();

                //We need to check this otherwise it will abort the request which we made from the
                //end request
                if (_executingElement != postBackElement)
                {
                    //Does not match which means it is another control
                    //which request the update, so cancel it temporary and 
                    //add it in the call queue
                    args.set_cancel(true);
                    Array.enqueue(_callQueue, postBackElement);
                }

                //Reset it as we are done with our matching
                _executingElement = null;
            }
        }

        function endRequest(sender, args)
        {
            //Check if we have a pending call
            if (_callQueue.length > 0)
            {
                //Get the first item from the call queue and setting it
                //as current executing item
                _executingElement = Array.dequeue(_callQueue);

                //Now Post the from which will also fire the initializeRequest
                _prm._doPostBack(_executingElement.id, '');
            }
        }
    }
}

if (typeof(Sys) != 'undefined')
{
    Sys.Application.notifyScriptLoaded();
}

The PageRequestManagerEx is a Static class which hooks the initializeRequest and endRequest events of the original PageRequestManager. Then in the initializeRequest it first checks if there is an ongoing update, if so it cancel the new request and adds the control in a queue which cause the postback. Then in the endRequest it check if there is any pending call in the queue, if so it executes it. This loops gets executed until all the call in the queue get completed.

Lets me know if you found any issue. I will  be also very curious to know why update panel does not behave like this?

Download : Complete Source

kick it on DotNetKicks.com

Posted on Wednesday, August 8, 2007 6:29 AM Asp.net Ajax , Tips/Tricks | Back to top


Comments on this post: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Thank you!!

I was about to write my own but then remembered seeing something on dotnetkicks about simultaneous update panels.
Left by Denny Ferrassoli on Aug 11, 2007 12:09 AM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
I quickly modified your code to allow passing of the EventArgument as well...

These 2 functions were modified:

function initializeRequest(sender, args)
{
if (_prm.get_isInAsyncPostBack())
{
//if we are here that means there already a call pending.

//Get the element which cause the postback
var postBackElement = args.get_postBackElement();

//We need to check this otherwise it will abort the request which we made from the
//end request
if (_executingElement != postBackElement)
{
// Grab the event argument value
var evArg = $get("__EVENTARGUMENT").value;

//Does not match which means it is another control
//which request the update, so cancel it temporary and
//add it in the call queue
args.set_cancel(true);
Array.enqueue(_callQueue, new Array(postBackElement, evArg));
}

//Reset it as we are done with our matching
_executingElement = null;
}
}

function endRequest(sender, args)
{
//Check if we have a pending call
if (_callQueue.length > 0)
{
//Get the first item from the call queue and setting it
//as current executing item
_executingElement = Array.dequeue(_callQueue);
var _element = _executingElement[0];
var _eventArg = _executingElement[1];


//Now Post the from which will also fire the initializeRequest
_prm._doPostBack(_element.name, _eventArg);
}
}
Left by Denny Ferrassoli on Aug 11, 2007 2:35 AM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Thats Great, Denny Thanks.
Left by Kazi Manzur Rashid on Aug 11, 2007 4:07 AM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
hi,

great article, minor correction: you've called pageRequestManager.getInstance() twice during init, one when declaring local variable _prm and 2 after initiliazing _callQueue and _executingElement

Left by bonskijr on Aug 13, 2007 5:37 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Hello,

Great article. One question, is there a way to make the UpdateProgress control display for the queued requests?
Left by Fred on Sep 04, 2007 11:17 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Can anybody tell if the requests can be executed simultaneously rather than queueing. I click button 1 at 12:40:20 and button 2 at 12:40:21, it should say result as 12:40:25 for the first and 12:40:26 for the second.

Thanks in advance.
Left by Ishfaq Hussain on Sep 10, 2007 11:29 AM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Really great tips, BUT,...
I cant seem to get it to work with Master Page.

I tried everything... (i must miss something).
I tried ScriptManagerProxy on the content page with ScriptReference set to the path of the js file.
I also tried to simply put this below onto the content page,
<script type="text/javascript">
PageRequestManagerEx.init();
</script>
still doesnt work.
Can you please point me to the right direction?
email is orangejim@gmail.com.
Appreciate it
Left by jim on Dec 16, 2007 5:02 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Great article but still i dont is there any why we can get simultaneos execution of requests rather than one after other.
Left by kushal on Dec 22, 2007 5:06 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Here is a fixed version of the javascript file which maintains the eventArguments.

----------------------------------------------------

var PageRequestManagerEx =
{
_initialized : false,

init : function()
{
if (!PageRequestManagerEx._initialized)
{
var _prm = Sys.WebForms.PageRequestManager.getInstance();
var _callQueue = new Array();
var _executingElement = null;

_prm = Sys.WebForms.PageRequestManager.getInstance();

_prm.add_initializeRequest(initializeRequest);
_prm.add_endRequest(endRequest);

PageRequestManagerEx._initialized = true;
}

function initializeRequest(sender, args)
{
if (_prm.get_isInAsyncPostBack())
{
//if we are here that means there already a call pending.

//Get the element which cause the postback
var postBackElement = args.get_postBackElement();

//We need to check this otherwise it will abort the request which we made from the
//end request
if (_executingElement != postBackElement)
{
// Grab the event argument value
var evArg = $get("__EVENTARGUMENT").value;

//Does not match which means it is another control
//which request the update, so cancel it temporary and
//add it in the call queue
args.set_cancel(true);
Array.enqueue(_callQueue, new Array(postBackElement, evArg));
}

//Reset it as we are done with our matching
_executingElement = null;
}
}

function endRequest(sender, args)
{
//Check if we have a pending call
if (_callQueue.length > 0)
{
//Get the first item from the call queue and setting it
//as current executing item
_executingElement = Array.dequeue(_callQueue);

var _element = _executingElement[0];
var _eventArg = _executingElement[1];

//Now Post the from which will also fire the initializeRequest
_prm._doPostBack(_element.id, _eventArg);
}
}

}
}

if (typeof(Sys) != 'undefined')
{
Sys.Application.notifyScriptLoaded();
}

-----------------------------------------
Left by Matthew on Feb 05, 2008 10:41 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Hi, great help, thanks... I'm using this piece of javascript on an intensive page, where I have some parts of the page that need to happen in the background.... their postbacks can be interrupted by other ajax controls on the page, but they need to be executed eventually... So they had to be sequentially executed, but sometimes delayed.... I made some adjustments, maybe someone else needs them too?

var PageRequestManagerEx =
{
_initialized : false,

init : function()
{
if (!PageRequestManagerEx._initialized)
{
var _prm = Sys.WebForms.PageRequestManager.getInstance();
var _callQueue = new Array();
var _executingElement = null;
var _executingEventArgs = null;

_prm = Sys.WebForms.PageRequestManager.getInstance();
_prm.add_initializeRequest(initializeRequest);
_prm.add_endRequest(endRequest);

PageRequestManagerEx._initialized = true;
}

function initializeRequest(sender, args)
{
if (_prm.get_isInAsyncPostBack())
{
//if we are here that means there already a call pending.

//Get the element which cause the postback
var postBackElement = args.get_postBackElement();

//We need to check this otherwise it will abort the request which we made from the
//end request

if (_executingElement != postBackElement)
{
// Grab the event argument value
var evArg = $get("__EVENTARGUMENT").value;

//Does not match which means it is another control
//which request the update, so cancel it temporary and
//add it in the call queue
if (evArg == 'lowPriority')
{
args.set_cancel(true);
Array.enqueue(_callQueue, new Array(postBackElement, evArg));
}
else
{
if (_executingEventArgs == 'lowPriority')
{
Array.enqueue(_callQueue, new Array(_executingElement, _executingEventArgs));
_executingElement = postBackElement;
_executingEventArgs = evArg;
}
}
}
}
else
{
_executingElement = args.get_postBackElement();
_executingEventArgs = $get("__EVENTARGUMENT").value;
}
}

function endRequest(sender, args)
{
//Check if we have a pending call
if (_callQueue.length > 0)
{
//Get the first item from the call queue and setting it
//as current executing item
var _queue = Array.dequeue(_callQueue);
_executingElement = _queue[0];
_executingEventArgs = _queue[1];

//Now Post the from which will also fire the initializeRequest
_prm._doPostBack(_executingElement.id, _executingEventArgs);
}
}
}
}

if (typeof(Sys) != 'undefined')
{
Sys.Application.notifyScriptLoaded();
}
Left by Rob on Feb 25, 2008 8:51 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
i used Matthew's version and it works perfectly

thank you!
Left by Patrick on Mar 10, 2008 7:55 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Thank you for the global idea on how to resolve this issue.

But I have to make a little precision : the first argument of a postback, which correspond to the __EVENTTARGET parameter, is not always the postback element id.

Just make a little website with all types of controls in an updatepanel to test it. You can use the method "Page.ClientScript.GetPostBackEventReference(Control c, string arguments)" on the server side to get the javascript instruction to make a postback from a control and compare the first parameter to the HTML elemnt attributes. It's offently the name attribute which is used but not always.

The best way to get the good parameter is to extract it from the initial postback request url parameters which are accessible like that in the initialize method :
args.get_request()._body

You have to extract the values for __EVENTTARGET and __EVENTARGUMENT parameters and use those in the postback call.

PoPy
Left by PoPy on Mar 18, 2008 8:19 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
hi all.
it`s not working when i use usercontrols, did any one tried the solution on usercontrols ?
Left by Amin on May 22, 2008 2:02 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
I want to get popup with data from database while writing in textbox.
Left by vivekanand on Sep 08, 2008 5:59 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Thanks a lot for your script. I've definitively aborted to develop real simultaneous doPostback calls.

Ayor
Left by Ayor on Oct 14, 2008 2:15 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Hello,

I need your help! ;) I used Matthew's version and it not works fine. When there are simultaneous 2 asyncpostbacks, the second asyncpostback not pass for the server event, but yes for de "initializeRequest" and "endRequest" client functions. Why? I can't find the solution. Can anyone help me?

Thanks!!
Left by Raquel on Oct 29, 2008 6:38 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Hello,

I forgot to tell in the previous post that control which updates my UpdatePanel is a "AsyncPostBackTrigger". Can it be for that? if so, how can I fix it?

Thanks!
Left by Raquel on Oct 29, 2008 6:47 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
I tried all the solutions provided here but the error is "Sys is undefined". I have added all kinds if libraries and handlers but the problem still exists.
Can some one help me out please!!!!!!!!!!!!!!!!!

Nick.
Left by Nick on Nov 18, 2008 9:27 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
Can anybody have a solution with MasterPages?

Thanks.
Left by Brezhon on Dec 17, 2008 4:04 PM

# re: Asp.net Ajax UpdatePanel Simultaneous Update - A Remedy
Requesting Gravatar...
If you have a masterPage :

replace _prm._doPostBack(_element.id, _eventArg);
with _prm._doPostBack(_element.name, _eventArg);

thanks for this script.
Left by Brezhon 29 on Dec 17, 2008 9:58 PM

Your comment:
 (will show your gravatar)
 


Copyright © Kazi Manzur Rashid | Powered by: GeeksWithBlogs.net | Join free