ASP.NET Controller: An asynchronous module or handler completed while an asynchronous operation was still pending

后端 未结 8 1186
一个人的身影
一个人的身影 2020-11-28 09:36

I have a very simple ASP.NET MVC 4 controller:

public class HomeController : Controller
{
    private const string MY_URL = \"http://smthing\";
    private r         


        
8条回答
  •  时光说笑
    2020-11-28 10:06

    ASP.NET considers it illegal to start an “asynchronous operation” bound to its SynchronizationContext and return an ActionResult prior to all started operations completing. All async methods register themselves as “asynchronous operation”s, so you must ensure that all such calls which bind to the ASP.NET SynchronizationContext complete prior to returning an ActionResult.

    In your code, you return without ensuring that DownloadAsync() has run to completion. However, you save the result to the task member, so ensuring that this is complete is very easy. Simply put await task in all of your action methods (after asyncifying them) prior to returning:

    public async Task IndexAsync()
    {
        try
        {
            return View();
        }
        finally
        {
            await task;
        }
    }
    

    EDIT:

    In some cases, you may need to call an async method which should not complete prior to returning to ASP.NET. For example, you may want to lazily initialize a background service task which should continue running after the current request completes. This is not the case for the OP’s code because the OP wants the task to complete before returning. However, if you do need to start and not wait for a task, there is a way to do this. You simply must use a technique to “escape” from the current SynchronizationContext.Current.

    • (not recommenced) One feature of Task.Run() is to escape the current synchronization context. However, people recommend against using this in ASP.NET because ASP.NET’s threadpool is special. Also, even outside of ASP.NET, this approach results in an extra context switch.

    • (recommended) A safe way to escape the current synchronization context without forcing an extra context switch or bothering ASP.NET’s threadpool immediately is to set SynchronizationContext.Current to null, call your async method, and then restore the original value.

提交回复
热议问题