2015-04-26 13 views
9

Ho un controller molto semplice MVC con una sola azione:Controller MVC non può eseguire il metodo asincrono

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     OpenConnection().Wait(); 

     return View(); 
    } 

    private async Task OpenConnection() 
    { 
     var synchronizationContext = SynchronizationContext.Current; 
     Debug.Assert(synchronizationContext != null); 

     using (
      var connection = 
       new SqlConnection(
        @"Data Source=(localdb)\ProjectsV12;Initial Catalog=Database1;Integrated Security=True;")) 
     { 
      await connection.OpenAsync(); // this always hangs up     
     } 
    } 
} 

Il problema è che l'azione regolare (non asincrona versione) non può eseguire metodi asincrone. Nel mio caso il metodo OpenConnection() riaggancia sempre a attende la connessione.OpenAsync() riga.

Dopo qualche tempo ho trovato due modi per far funzionare questo codice.

  1. asincrono azione del controller Marchio

    public async Task<ActionResult> Index() 
    { 
        await OpenConnection(); 
    
        return View(); 
    } 
    
  2. o consentire l'esecuzione asincrona senza catturare SychronizationContext originale - per questo:

    await connection.OpenAsync();

    sostituirli con:

    await connection.OpenAsync().ConfigureAwait(false);

Quindi, la mia ipotesi è che il mio problema iniziale era da qualche parte intorno a SynchronizationContext. Ma SynchronizationContext.Current non è nullo e mi chiedo se la mia ipotesi è corretta.

Quindi, qualcuno potrebbe spiegare, perché l'azione non asincrona nel controller MVC non può eseguire i metodi asincroni in modo sincrono?

risposta

10

Stephen Cleary ha un good blog post about this issue e ha effetto sia su ASP.NET che sulle app desktop. L'essenza di base è che poiché il contesto (contesto di richiesta ASP.NET nel tuo esempio) viene bloccato in modo sincrono dalla tua chiamata .Wait() esplicita, l'attività asincrona non può eseguire codice nel contesto per notificare che è stato completato così è deadlock.

Propone anche le stesse due soluzioni (utilizzare async fino in fondo dal metodo del controller di primo livello o modificare il codice "libreria" asincrono per non acquisire il contesto).

Problemi correlati