views:

257

answers:

3

I want to provide status updates during a long-running task on an ASP.NET WebForms page with AJAX.

Is there a way to get the ScriptManager to execute and process a script for a web service request concurrently with an async postback?

I have a script on the page that makes a web service request. It runs on page load and periodically using setInterval(). It's running correctly before the async postback is initiated, but it stops running during the async postback, and doesn't run again until after the async postback completes.

I have an UpdatePanel with a button to trigger an async postback, which executes the long-running task. I also have an instance of an AJAX WCF Web service that is working correctly to fetch data and present it on the page but, like I said, it doesn't fetch and present the data until after the async postback completes.

During the async postback, the long-running task sends updates from the page to the web service.

The problem is that I can debug and step through the web service and see that the status updates are correctly set, but the updates aren't retrieved by the client script until the async postback completes.

It seems the Script Manager is busy executing the async postback, so it doesn't run my other JavaScript via setInterval() until the postback completes.

Is there a way to get the Script Manager, or otherwise, to run the script to fetch data from the WCF web service during the async postback?

I've tried various methods of using the PageRequestManager to run the script on the client-side BeginRequest event for the async postback, but it runs the script, then stops processing the code that should be running via setInterval() while the page request executes.

A: 

The ajax plumbing may be queuing your requests.

Try making the status call manually with an XHR or jQuery. You may find that solves the problem.

But... keep in mind that there are a finite number of concurrent requests that can be happening at one time and that once the limit is reached blocking starts to happen.

This limit varies by browser/version.

Sky Sanders
A: 

Upon further inspection with Web Developent Helper, it appears that the web service requests are being made at the interval I set (5 secs), but the first request during the long-running task takes the duration of the task to return a result, while subsequent requests continue to return nothing. When the task completes, the first web service request sent when the task began returns with the status data.

I've been trying to figure out why the initial request to the web service doesn't return until the task completes. Session variables may not be updated until the end of the AsyncPostBack request, so I tried the ASP.NET cache, but that doesn't work either. I tried a local variable with the web service, both in InstanceContextMode.PerSession and InstanceContextMode.Single modes.

I've been following the example from MSDN Mag: July 2007: Cutting Edge, but using the ASP.NET cache doesn't seem to help with the AsyncPostBack. I'm going to try calling WebMethod methods in my code-behind directly instead of the AsyncPostBack, but the articles says it should work, so I'd like to figure out why my implementation doesn't.

So:

  1. Page loads.
  2. setInterval('getUpdate()', 5000) starts.
  3. getUpdate() calls a web service and returns emtpy data every 5 secs.
  4. User clicks the button to start an AsyncPostBack in an UpdatePanel.
  5. Server-side processing starts on the long-running task.
  6. getUpdate() calls the web service. The request is pending.
  7. The long-running task proceeds.
  8. getUpdate() continues to call the web service every 5 secs. Each request returns empty data.
  9. The long-running task completes.
  10. The AsyncPostBack completes and returns a response to the browser.
  11. The outstanding web service request is sent a response.
  12. getUpdate() returns the web service response and updates the page to display the result.
nekno
A: 

A follow-up with a solution for anyone that may find this in the future.

I tried sending the request in a multitude of ways:

  • The AJAX script objects created when you add the WCF service as a ServiceReference to the ScriptManager. So, if the WCF service class is ProgressService with a GetProgress method, I created a new ProgressService object in JavaScript and called progressService.GetProgress().
  • An XmlHttpRequest request.
  • A jQuery $.getJson() request.
  • A Sys.Net.WebRequest request.
  • A Sys.Net.WebServiceProxy request.

It turns out that even if the client request is sent, i.e., not buffered by the ASP.NET ScriptManager, that the WCF service won't respond if it is part of the same website in IIS.

So rather than creating an entirely separate WCF project, and an entirely separate IIS website, I switched to a traditional ASP.NET (SOAP) web service (.asmx).

I was able to keep the .asmx service part of the same project in Visual Studio, and website in IIS. The request is sent during a postback, and the service responds during a postback.

After adding it as a ServiceReference under the ScriptManager, I was also able to use essentially the same scripting objects, creating a new ProgressWebService(), then calling progressWebService.GetProgress(). A callback handler passed to GetProgress() then handles the response and updates the UI.

nekno