2012-07-05 17 views
7

sto solo usando le nuove funzioni asincrone controller in MVC 4, come descritto qui http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4ASP.NET MVC 4 controller asincrono richiamata

Se ho un'azione che può richiedere 10-20 secondi per eseguire vorrei fornire una sorta di barra di stato per informare l'utente del progresso. Le funzionalità Async hanno qualcosa per aiutare questo fuori?

EDIT: mi prenderò una pugnalata a come cercherò di farlo e vedere se ci sono modi migliori

public async Task<ActionResult> GizmosAsync() 
{ 
    return View("Gizmos", await GetGizmosAsync()); 
} 

private void GetGizmosAsync() 
{ 
    for(int i=0; i<10; i++) 
    { 
     lock(_locker) 
     { 
      _statusMessage = String.Format("{0} of 10", i); 
     } 
     DoSomethingLongRunning(); 
    } 
} 

public ActionResult Status() 
{ 
    return Json(new { Status = _statusMessage }); 
} 

static readonly object _locker = new object(); 

static string _statusMessage = ""; 

.... 

<script> 

setTimeout(displayStatus, 1000); 

function displayStatus() { 
    $.post("/controller/status", function(data) { 
    alert(data.Status); 
    }); 
} 

</script> 

risposta

15

controller asincroni è solo un meccanismo per liberare le discussioni dal ThreadPool in IIS in modo essere in grado di gestire le richieste in arrivo durante il carico pesante, ma la comunicazione con il cliente rimane come la normale richiesta-risposta.

Le barre di stato e l'ordinamento in genere sono solo javascript che visualizzano qualcosa sullo schermo finché non termina la richiesta Ajax. Non penso che MVC4 sarà di aiuto in quella parte.

Si potrebbe fare qualcosa del genere: https://stackoverflow.com/a/68503/1373170 per visualizzare un "elaborazione ..." <div> durante le chiamate Ajax.

EDIT: Se avete bisogno di progresso del cliente reale e l'interazione (come ad esempio il progresso reale), si dovrebbe verificare SignalR http://www.hanselman.com/blog/AsynchronousScalableWebApplicationsWithRealtimePersistentLongrunningConnectionsWithSignalR.aspx E questo post correlati: Async Controllers (MVC), long running process with "stops"

+0

Sì, ho già fare qualcosa di simile, ma se è lo stesso messaggio per 10 secondi la gente pensa il sistema è bloccato. – Craig

+0

Beh, so che potrebbe non sembrare appropriato, ma a volte l '"illusione" del progresso è proprio ciò di cui gli utenti hanno bisogno. Ad esempio, se sai che il tuo compito richiede in media 15 secondi, automatizza una barra di avanzamento attraverso quella durata usando js. So che può sembrare che stia ingannando l'utente, ma in realtà ci sono alcuni casi in cui in realtà memorizza il progresso parziale da qualche parte, come un database e il tuo polling sul lato client per il progresso esatto è semplicemente eccessivo. –

+0

Non avevo pensato a SignalR, probabilmente avrebbe funzionato bene. – Craig

5

questo articolo sembra descrivere ciò che si desiderare:

ASP.NET MVC 3: Async jQuery progress indicator for long running tasks

controller:

public class HomeController : Controller 
{ 
    private static IDictionary<Guid, int> tasks = new Dictionary<Guid, int>(); 

    public ActionResult Index() 
    { 
     return View(); 
    } 

    public ActionResult Start() 
    { 
     var taskId = Guid.NewGuid(); 
     tasks.Add(taskId, 0); 

     Task.Factory.StartNew(() => 
     { 
      for (var i = 0; i <= 100; i++) 
      { 
       tasks[taskId] = i; // update task progress 
       Thread.Sleep(50); // simulate long running operation 
      } 
      tasks.Remove(taskId); 
     }); 

     return Json(taskId); 
    } 

    public ActionResult Progress(Guid id) 
    { 
     return Json(tasks.Keys.Contains(id) ? tasks[id] : 100); 
    } 
} 

Vista:

<script type="text/javascript"> 

function updateMonitor(taskId, status) { 
    $("#" + taskId).html("Task [" + taskId + "]: " + status); 
} 

$(function() { 
    $("#start").click(function (e) { 
    e.preventDefault(); 
    $.post("Home/Start", {}, function (taskId) { 

    // Init monitors 
    $("#monitors").append($("<p id='" + taskId + "'/>")); 
    updateMonitor(taskId, "Started"); 

    // Periodically update monitors 
    var intervalId = setInterval(function() { 
     $.post("Home/Progress", { id: taskId }, function (progress) { 
     if (progress >= 100) { 
      updateMonitor(taskId, "Completed"); 
     clearInterval(intervalId); 
     } else { 
      updateMonitor(taskId, progress + "%"); 
     } 
     }); 
     }, 100); 
    }); 
    }); 
}); 
</script> 
<div id="monitors"></div> 
+1

Non valido se si utilizza un ambiente AppDomain multiplo con bilanciamento del carico. – divinci