ASP.NET MVC中的Task.Run与ContinueWith

Seb*_*ski 8 c# asp.net asp.net-mvc task-parallel-library async-await

在我的ASP.NET MVC 4应用程序中,假设我有一些async方法:

async Task DoSomeBackgroundWork()
{
   // Fake it
   await Task.Delay(5000);
}
Run Code Online (Sandbox Code Playgroud)

现在,可以像这样调用这个方法:

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

或这个:

DoSomeBackgroundWork()
  .ContinueWith(t => Debug.WriteLine("Background work finished"));
Run Code Online (Sandbox Code Playgroud)

请注意,在两个版本中,调用者都不会等待后台任务完成.这只是火和忘记.

虽然两个版本在常规.NET应用程序上相同(忽略异常处理),但在MVC应用程序上,从MVC控制器方法调用代码时,Debug.WriteLine只在Task.Run版本中执行- 但不在ContinueWith版本中执行.

任何人都可以了解为什么这两个版本在MVC控制器方法中调用时的工作方式不同?

nos*_*tio 5

这可能是您的网络应用程序特有的,所以我只能推测,但这是我的想法:

  • 它应该工作如果你这样做:

    DoSomeBackgroundWork()
        .ContinueWith(t => Debug.WriteLine("Background work finished"), 
            TaskContinuationOptions.ExecuteSynchronously);
    
    Run Code Online (Sandbox Code Playgroud)

    这将更接近于Task.Run版本,其中延续同步运行.

  • 在您DoSomeBackgroundWork直接从控制器方法调用之前,添加以下内容:

    Debug.WriteLine(new { TaskScheduler.Current });
    
    Run Code Online (Sandbox Code Playgroud)

    如果输出是什么,但ThreadPoolTaskScheduler,我也许可以进一步解释这种行为(因为我刚刚处理了一个有点相关的问题在这里).

顺便说一句,在ASP.NET中使用fire-and-forget这样做真的不是一个好主意,有很多关于SO讨论这个的问题.