Geeks With Blogs
Amit's Blog Sharing Thoughts and Learning

In this post I will show you how to cancel a web Service call after it is invoked, I will also provide you some interesting findings (Maybe a Bug) in Asp.net Ajax Network Layer. There are plenty of examples available on how to abort an UpdatePanel AsyncPostback but none for the WebService. The following will show you how to do it.

Since we are going to cancel a call we need a  web method which wait for a long time to complete:

The Web Method:

[WebMethod()]
public string LongOperation(int miliseconds)
{
    System.Threading.Thread.Sleep(miliseconds);
    return "Task Complete";
}

Now lets check the client part. If you are already familiar with Web Service calling in JavaScript, I hope you know that there is always a JavaScript Proxy class involved for that Web Service. This Proxy class is inherited from the Sys.Net.WebServiceProxy which contains a single method invoke. If you check the Ajax Documentation you will find that this invoke method returns a WebRequest object which is used to call Web Service method, it is also mentioned that this WebRequest object can be also used to cancel the call. Now lets see what is the generated Proxy class looks like. You can easily generate the proxy class by appending /js in the Web Service URL. 

var TestService=function() {
TestService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
TestService.prototype={
LongOperation:function(miliseconds,succeededCallback, failedCallback, userContext) {
return this._invoke(TestService.get_path(), 'LongOperation',false,{miliseconds:miliseconds},succeededCallback,failedCallback,userContext); }}
TestService.registerClass('TestService',Sys.Net.WebServiceProxy);
TestService._staticInstance = new TestService();
TestService.set_path = function(value) { TestService._staticInstance.set_path(value); }
TestService.get_path = function() { return TestService._staticInstance.get_path(); }
TestService.set_timeout = function(value) { TestService._staticInstance.set_timeout(value); }
TestService.get_timeout = function() { return TestService._staticInstance.get_timeout(); }
TestService.set_defaultUserContext = function(value) { TestService._staticInstance.set_defaultUserContext(value); }
TestService.get_defaultUserContext = function() { return TestService._staticInstance.get_defaultUserContext(); }
TestService.set_defaultSucceededCallback = function(value) { TestService._staticInstance.set_defaultSucceededCallback(value); }
TestService.get_defaultSucceededCallback = function() { return TestService._staticInstance.get_defaultSucceededCallback(); }
TestService.set_defaultFailedCallback = function(value) { TestService._staticInstance.set_defaultFailedCallback(value); }
TestService.get_defaultFailedCallback = function() { return TestService._staticInstance.get_defaultFailedCallback(); }
TestService.set_path("TestService.asmx");
TestService.LongOperation= function(miliseconds,onSuccess,onFailed,userContext) {TestService._staticInstance.LongOperation(miliseconds,onSuccess,onFailed,userContext); }

As you can see the LongOperation in protoype section is using the base class(Sys.Net.WebServiceProxy) invoke method to call the Web method which in turn returns WebRequest. The Proxy also has a self instance as a _staticInstance. But in later it overrides the method and uses the _staticInstance to call the WebMethod but it does not return the WebRequest(This is the bug) in this case. So if I write the code as we always did for calling a web method it does not return the WebReqest object.

var _request = TestService.LongOperation    (       10000, //10 seconds
                                                    function(result)
                                                    {
                                                        //
                                                    },
                                                    function(exception)
                                                    {
                                                        //
                                                    }
                                            );


But if I call like the following the WebRequest is returned:

var _request = TestService._staticInstance.LongOperation  (     10000, //10 seconds
                                                            function(result)
                                                            {
                                                                //
                                                            },
                                                            function(exception)
                                                            {
                                                                //
                                                            }
                                                        );

Really interesting!!! I have already posted a bug in Asp.net Ajax Forum you can check the progress from this link.

Now lets check how to cancel the call as we have already got the reference of the WebRequest object. To Cancel we can use the following code:

if (_request != null)
{
    var executor = _request.get_executor();

    if (executor.get_started())
    {
        executor.abort();
    }
}

Explanation: Every WebRequest in Ajax Framework has an associated Executor which actually uses the browser XMLHttpRequest to call the server side method (An URL).  In the above, first we are getting a reference of that executor then checking if the call is in progress (To be in the safe side), if so then we are invoking abort method of that executor which in turns call the abort method of the XMLHttpRequest.

Another annoying problem I found after doing the abort the Ajax Framework throws an exception and for this reason the OnFailure Callback of the Web method call is executed. So we also need to differentiate between a real exception and an User Defined Abort (May be a button click of the user). For this we have to put some extra check in the failure callback like the following:

 

var _request = TestService._staticInstance.LongOperation  (     10000, //10 seconds
                                                                function(result)
                                                                {
                                                                    alert(result);
                                                                    $get('btnInvoke').disabled = false;
                                                                    $get('btnAbort').disabled = true;
                                                                },
                                                                function(exception)
                                                                {
                                                                    if (!_request.get_executor().get_aborted())
                                                                    {
                                                                        alert(exception.get_message());
                                                                    }
                                                                    $get('btnInvoke').disabled = false;
                                                                    $get('btnAbort').disabled = true;
                                                                }
                                                            );

In the Failure Callback we are again checking if the WebRequest Executor has been aborted, if so then it is not an exception rather the user choose to cancel the call.

Download: Complete working sample.

kick it on DotNetKicks.com

Posted on Saturday, July 14, 2007 5:30 AM Asp.net , Asp.net Ajax , Tips/Tricks | Back to top


Comments on this post: Cancel a Web Service Call in Asp.net Ajax

# re: Cancel a Web Service Call in Asp.net Ajax
Requesting Gravatar...
Those are great findings! But the sample isn't referring to the issue.
Left by Joao on Aug 30, 2007 11:56 PM

# re: Cancel a Web Service Call in Asp.net Ajax
Requesting Gravatar...
I am not sure what do you mean. Are not you able to cancel the call with the provided code?
Left by Kazi Manzur Rashid on Aug 31, 2007 1:20 AM

# re: Cancel a Web Service Call in Asp.net Ajax
Requesting Gravatar...
is this way better??
Left by AI-experts on Apr 26, 2008 11:31 PM

# re: Cancel a Web Service Call in Asp.net Ajax
Requesting Gravatar...
When I try to cancel the call using abort I am getting an error

"The server method '<WebMethodName>' failed";

did you get this error.
Left by .NET on May 16, 2008 4:13 AM

Your comment:
 (will show your gravatar)
 


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