8

In my ASP.NET MVC 4 application, say I have some async method:

async Task DoSomeBackgroundWork() { // Fake it await Task.Delay(5000); } 

Now, one can call this method like this:

Task.Run(async () => { await DoSomeBackgroundWork(); Debug.WriteLine("Background work finished"); }); 

or this:

DoSomeBackgroundWork() .ContinueWith(t => Debug.WriteLine("Background work finished")); 

Note that in both versions the caller doesn't wait for the background task to finish. It's just fire and forget.

While both versions work identical (ignore exception handling here) on regular .NET apps, on a MVC app, when calling the code from a MVC controller method, Debug.WriteLine is only executed in the Task.Run version - but not in the ContinueWith version.

Can anyone shed some light onto why these two versions are working differently when called in a MVC controller method?

7
  • Works fine for me too. Popped into Global.asax in a .NET4.5 Web App Commented Apr 15, 2014 at 9:31
  • @Noseratio It actually currently does look that way. Commented Apr 15, 2014 at 9:36
  • 2
    Add Debug.WriteLine(new { SynchronizationContext.Current }); inside and outside DoSomeBackgroundWork, everywhere. Do you see AspNetSynchronizationContext or LegacyAspNetSynchronizationContext anywhere? (what and where exactly?) Commented Apr 15, 2014 at 9:40
  • @SriramSakthivel Thats the point! In Console it works fine for instance. But not in MVC. Commented Apr 15, 2014 at 9:50
  • 1
    @Noseratio Inside the controller method (caller), the context is AspNetSynchronizationContext. Inside of DoSomeBackgroundWork(), it's also AspNetSynchronizationContext when calling it directly from the controller method; and it's null when DoSomeBackgroundWork() is called from within Task.Run(). Commented Apr 15, 2014 at 9:51

1 Answer 1

5

This is probably something specific to your web app, so I can only speculate, but here's what I think:

  • It should work if you do this:

    DoSomeBackgroundWork() .ContinueWith(t => Debug.WriteLine("Background work finished"), TaskContinuationOptions.ExecuteSynchronously); 

    This would be more close to the Task.Run version, where the continuation runs synchronously.

  • Right before you call DoSomeBackgroundWork directly from the controller method, add this:

    Debug.WriteLine(new { TaskScheduler.Current }); 

    If the output is anything but ThreadPoolTaskScheduler, I might be able to further explain this behavior (as I've just dealt with a somewhat related problem here).

BTW, using fire-and-forget in ASP.NET like this is really not a good idea, there's a lot of questions on SO discussing this.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.