This past week, I had a bug assigned to me about a user canceling a long running process in their browser, but it kept running on the server. It was a process to generate PDF files, and the component we use is kind of memory intensive. As a result, having it run for no reason is troublesome. And of course, there's always the possibility that the user goes back and kicks off the process again, doubling the number of resources used.
There were a solution that immediately popped into my mind: make it asynchronous, and have a way to indicate to the user that it's done, and give them away to pick up the files on demand. This frees them up to move on to do other things, and solves the original problem. It's a good long term fix, and one we'll eventually move to.
But the question was more about being able to find a way to cancel the processing if the user left the page. Could we do that, deploy a quick fix that alleviated the resource hog, and give us some breathing room to implement the long-term fix?
It looks like the answer is yes. I hadn't run across it's usage very often before, but you can use Response.IsClientConnected to see if the browser is still waiting for the request to complete. You can check it periodically, and if the client has moved on, then you can cancel processing. In our case, we were generating a number of PDFs in a loop, so checking every time around worked fine, and the code is rather simple:
1: public void GeneratePdfs()
2: {
3: foreach(var pdf in PdfList)
4: {
5: // Get PDF Data and write it out
6:
7: if (!Response.IsClientConnected)
8: {
9: Response.End();
10: }
11: }
12:
13: // Zip PDFs and send to browser.
14: }
I wrote a quick test page to verify how it works, and fired up the debugger to watch the output window. Here was my Page_Load method:
1: protected void Page_Load(object sender, EventArgs e)
2: {
3: while (true)
4: {
5: if (Response.IsClientConnected)
6: {
7: Debug.WriteLine("Connected");
8: }
9: else
10: {
11: Debug.WriteLine("Disconnected");
12: break;
13: }
14: }
15: }
Firing up the browser (I tested in IE and Firefox) and navigating to the page showed a steady stream of "Connected" in the output window. Closing the browser immediately wrote out "Disconnected", as did clicking back or navigating to another page. The only case I could find that didn't react as I'd expect was clicking stop or hitting escape on the page. It still showed as connected. Only after navigating to another page or closing the browser did it get the disconnected message. Still, in most cases, it's better than letting the process run it's course for no reason.
I know in this case, doing it asynchronously is the long term solution, but I'm sure in some cases, this will come in handy. And of course, I want to make sure it's the best way to handle it, so if you've done something similar, or better yet, better, what was it?