Friday 15 April 2011

ASP.NET AJAX: Calling PageMethods Synchronously

Hi,

Few days back i had a situation where i need to call PageMethods synchronously. But as you all know PageMethods are asynchronous call with callbacks for Success and Failure cases.
There are many tutorials which explains What are PageMethods and How to use PageMethods? So I'm not focusing into this.

Now, In order to call PageMethods synchronously we have to use following javascript code before calling a PageMethod:

<script type="text/javascript" language="javascript">
  
XMLHttpRequest.prototype.original_open = XMLHttpRequest.prototype.open;
 

XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
 

async = false;
 

var eventArgs = Array.prototype.slice.call(arguments);

return this.
original_open.apply(this, eventArgs);

// Call to your PageMethods

</script>


Code Understanding:
PageMethods are called using open method exposed via XMLHttpRequest object.
Now open method is called with 5 parameters as seen above, one of which specifies whether the call will be synchronous or not and the parameter name is async (true by default).
Here we have to change this async parameter to false and this is done using above javascript code in steps as:
1. First Saved the original open function to another variable named as original_open.
2. Modified original open function to make async parameter to false and finally called original_open (created in step 1.) method with all original parameters except for async parameter which we have changed to false.

Remember once you execute this javascript code all PageMethods call will be synchronous.

Now if you want some of your PageMethod calls should be synchronous and some not, then you will have to change code as:

<script type="text/javascript" language="javascript">

var asyncState = true;
 
XMLHttpRequest.prototype.original_open = XMLHttpRequest.prototype.open;

XMLHttpRequest.prototype.open = function(method, url, async, user, password) {

    async =
asyncState;

    var eventArgs = Array.prototype.slice.call(arguments);

    return this.original_open
.apply(this, eventArgs);
}

</script>


If you want to make a Synchronous PageMethod call, use asyncState = false before calling your PageMethod as:
asyncState = false;
PageMethods.HelloWorld(onSuccess, onError);



And for Asynchronous PageMethod  call:
asyncState = true;
PageMethods.HelloWorld(onSuccess, onError);


Note:  HelloWorld is a method exposed as a PageMethod and onSuccess and onError are callbacks in javascript for success and failure respectively.

Demo:
Expose a method in your page as PageMethod using WebMethod attribute:

Default.aspx.cs
[System.Web.Services.WebMethod]
    public static string HelloWorld()
    {

        System.Threading.Thread.Sleep(1000);
        return "Hello from server side";
    }


This method will just return a string "Hello from server side".
System.Threading.Thread.Sleep(1000) is used to hold the PageMethod call for 1 sec.

Default.aspx
Now create a javascript function to call this PageMethod with callbacks OnSuccess and OnFailure.
function JavascriptHelloWorld() {
            PageMethods.HelloWorld(onSuccess, onError);
            alert("End of Javascript Method");
        }


function onSuccess(result) {
            alert(result);
        }

function onError(result) {
            alert("Error");
        }


At the end of function, JavascriptHelloWorld alert is fired indicating end of function is reached.


Now call function, JavascriptHelloWorld on click of button as:
<input type="button" value="Hello World" onclick="JavascriptHelloWorld();" />

In normal case, onclick of button alert "End of Javascript Method" will be shown first followed by
"Hello from server side" (This delay is due to System.Threading.Sleep(1000);)
This shows that PageMethod call was asynchronous.


Now to call this PageMethod synchronously execute code mentioned at top and then call JavascriptHelloWorld(); now you will see alert "Hello from server side" followed by "End of Javascript Method"  
This shows that PageMethod call was synchronous.

7 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thanks Abhijit. It is very much helpful for me.

    ReplyDelete
  3. Welcome Dhinesh.
    And if you need more information you are always welcome.

    ReplyDelete
  4. Thank you soo much Abhijit. I was trying to achive this without using AJAX. but none of the other solutions worked... But yours worked like charm !!

    ReplyDelete
  5. Excelent ! I was soo looking for this ! Thank you very much !
    PS there is a } missing after the return this.original_open.apply(this, eventArgs); in case somebody copy code and does not notice.
    This blog looks very useful.

    ReplyDelete
  6. Excellent. Solved my problem!

    ReplyDelete