I have an asynchronous operation that for various reasons needs to be triggered using an HTTP call to an ASP.NET web page. When my page is requested, it should start this operation and immediately return an acknowledgment to the client.
This method is also exposed via a WCF web service, and it works perfectly.
On my first attempt, an exception was thrown, telling me:
Asynchronous operations are not allowed in this context. Page starting an asynchronous operation has to have the Async attribute set to true and an asynchronous operation can only be started on a page prior to PreRenderComplete event.
So of course I added the Async='true' parameter to the @Page directive. Now, I’m not getting an error, but the page is blocking until the Asynchronous operation completes.
How do I get a true fire-and-forget page working?
Edit: Some code for more info. It’s a bit more complicated than this, but I’ve tried to get the general idea in there.
public partial class SendMessagePage : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string message = Request.QueryString['Message']; string clientId = Request.QueryString['ClientId']; AsyncMessageSender sender = new AsyncMessageSender(clientId, message); sender.Start(); Response.Write('Success'); } }
The AsyncMessageSender class:
public class AsyncMessageSender { private BackgroundWorker backgroundWorker; private string client; private string msg; public AsyncMessageSender(string clientId, string message) { this.client = clientId; this.msg = message; // setup background thread to listen backgroundThread = new BackgroundWorker(); backgroundThread.WorkerSupportsCancellation = true; backgroundThread.DoWork += new DoWorkEventHandler(backgroundThread_DoWork); } public void Start() { backgroundThread.RunWorkerAsync(); } ... // after that it's pretty predictable }
If you don’t care about returning anything to the user, you can just fire up either a separate thread, or for a quick and dirty approach, use a delegate and invoke it asynchrnously. If you don’t care about notifying the user when the async task finishes, you can ignore the callback. Try putting a breakpoint at the end of the SomeVeryLongAction() method, and you’ll see that it finishes running after the page has already been served up: