Return to View with Async Await

I have a process I would like to run in the background. This is executed with a click of an action link.

Action to call:

   public async Task<ActionResult> ProcessRec()
   {
        await Task.Run(() => waitTimer());
        return RedirectToAction("Index", "Home");
   }

   public void waitTimer()
   {
        Thread.Sleep(10000);
   }

This however waits for the full 10 seconds before redirecting me to my “Index, Home” action. I am very new to Await/Async so I know I am interpreting something wrong here. How do I get the application to return to this action, while the waitTimer is executing in the background? Thanks!!

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

await, as you found out, blocks the response from returning to the user before it is done. Normally you would just put your background work on another thread and set it to “fire and forget” by not awaiting, however in ASP.NET IIS will shut down AppDomains that are not being used and Task.Run does not inform IIS that your background thread “is using the AppDomain” so your background thread could be terminated with a Thread.Abort() during an AppDomain shutdown.

If you are using .NET 4.5.2 or newer you can tell IIS you have a background worker that you need to be kept alive via QueueBackgroundWorkItem. You would use it like this

   public ActionResult ProcessRec()
   {
        HostingEnvironment.QueueBackgroundWorkItem(waitTimer);
        return RedirectToAction("Index", "Home");
   }

   public void waitTimer(CancellationToken token)
   {
        Thread.Sleep(10000);
   }
   //You also could do
   public async Task waitTimer2(CancellationToken token)
   {
        await Task.Delay(10000);
   }

Now this does not guarantee that IIS will not shut down your app domain but it does let it know you are in the middle of something and asks for more time when it does try to shut it down (You get up to 90 additional seconds after a shutdown is started to complete all queued background items by default).

For more information read this MSDN blog introducing it.

Method 2

This however waits for the full 10 seconds before redirecting me to my “Index, Home” action.

Right, that’s because await asynchronously waits for the operations completion. It will yield the thread back to the pool until the operation completes.

How do I get the application to return to this action, while the waitTimer is executing in the background?

Task.Run is dangerous in the fact it doesn’t register work with IIS which can lead to problems. Instead, you can use BackgroundTaskManager or HangFire which register it’s execution with ASP.NET:

BackgroundTaskManager.Run(() => { waitTimer() };
return RedirectToAction("Index", "Home");

Method 3

I’m thinking about sending a message to a queue (like azure storage/service bus queue) so that you can get your response immediately.

And then create another service to dequeue and process the message (execute your long running task)

Also if this is an azure website (web app), you can use the web job!

Hope that helps.

Method 4

public async Task<IActionResult> Index()
    {
        return await Task.Run(() =>
        {
            return View();
        });
    }


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x