Gestire il timeout in un controller asincrono di ASP.NET MVC 4

di Marco De Sanctis, in ASP.NET 4.5, ASP.NET MVC,

Quando realizziamo una Action asincrona all'interno di un controller, che magari esegue chiamate esterne e può avere una durata consistente, può essere opportuno stabilire un timeout a seguito del quale l'operazione debba essere annullata. Per questo scopo possiamo utilizzare l'attributo AsyncTimeout:

[AsyncTimeout(1000)]
public async Task<ActionResult> Index(CancellationToken token)
{
  var model = new MyModel();

  model.FirstValue = await serviceClient.VeryLongOperationAsync();
  model.SecondValue = await serviceClient.AnotherVeryLongOperationAsync();

  return this.View(model);
}

Nel codice in alto abbiamo impostato un timeout di 1 secondo per eseguire le due chiamate asincrone. Come possiamo notare, è necessario specificare come parametro della action un CancellationToken, che verrà utilizzato da ASP.NET per segnalarci l'eventuale scadenza del timeout.

Immaginiamo che la prima chiamata duri talmente tanto da superare da sola il tempo a disposizione. In questo caso, ASP.NET solleva una TimeoutException nella pipeline di risposta, e quindi non restituirà mai la View desiderata, sebbene l'esecuzione della action continuerà in ogni caso sino al suo termine. In questo caso, può essere sensato evitare chiamate inutili e terminarne l'esecuzione, verificando se è stata richiesta una cancellazione dell'operazione tramite il token:

[AsyncTimeout(1000)]
public async Task<ActionResult> Index(CancellationToken token)
{
  var model = new MyModel();

  model.FirstValue = await serviceClient.VeryLongOperationAsync();
  token.ThrowIfCancellationRequested();
  
  model.SecondValue = await serviceClient.AnotherVeryLongOperationAsync();
  token.ThrowIfCancellationRequested();
 
  return this.View(model);
}

Grazie a ThrowIfCancellationRequested, infatti, possiamo sollevare un'eccezione nel caso in cui l'operazione sia stata cancellata, interrompendo di fatto l'esecuzione del metodo del controller.

Per migliorare l'esperienza utente, possiamo eventualmente prevedere una pagina di errore apposita, per esempio utilizzando l'attributo HandleError sulla action:

[AsyncTimeout(100), 
 HandleError(ExceptionType=typeof(TimeoutException), View="timeout")]
public async Task<ActionResult> Index(CancellationToken token)
{
  // .. codice qui ..
}

Affinché funzioni, ovviamente, è necessario abilitare i custom error su web.config.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi