Page 120 - CSharp/C#
P. 120

public async Task<ActionResult> Index()
         {
             // Execution on the initially assigned thread
             List<Product> products = await dbContext.Products.ToListAsync();

             // Execution resumes on a "random" thread from the pool
             return View(products);
         }

         public ActionResult IndexSync()
         {
             Task<ActionResult> task = Index();

             // Block waiting for the result synchronously
             ActionResult result = Task.Result;

             return result;
         }


        This is because, by default the awaited task, in this case db.Products.ToListAsync() will capture the
        context (in the case of ASP.NET the request context) and try to use it once it has completed.


        When the entire call stack is asynchronous there is no problem because, once await is reached
        the original thread is release, freeing the request context.

        When we block synchronously using Task.Result or Task.Wait() (or other blocking methods) the
        original thread is still active and retains the request context. The awaited method still operates
        asynchronously and once the callback tries to run, i.e. once the awaited task has returned, it
        attempts to obtain the request context.

        Therefore the deadlock arises because while the blocking thread with the request context is
        waiting for the asynchronous operation to complete, the asynchronous operation is trying to obtain
        the request context in order to complete.


        ConfigureAwait


        By default calls to an awaited task will capture the current context and attempt to resume
        execution on the context once complete.


        By using ConfigureAwait(false) this can be prevented and deadlocks can be avoided.


         public async Task<ActionResult> Index()
         {
             // Execution on the initially assigned thread
             List<Product> products = await dbContext.Products.ToListAsync().ConfigureAwait(false);

             // Execution resumes on a "random" thread from the pool without the original request
         context
             return View(products);
         }

         public ActionResult IndexSync()
         {
             Task<ActionResult> task = Index();




        https://riptutorial.com/                                                                               66
   115   116   117   118   119   120   121   122   123   124   125