2014-07-18 7 views
7

Sto tentando di implementare una funzionalità in cui è presente una stored procedure su SQL Server che deve essere chiamata dall'applicazione ASP MVC ed elaborata sullo sfondo (potrebbe richiedere molto tempo poiché chiama un'altra stored procedure in remoto per elaborare un file Excel memorizzato su un server). Ma la risposta dell'ultima richiesta HTTP dovrebbe essere restituita al client, quindi l'interfaccia utente non sarà sospesa in attesa dell'elaborazione.Esegui attività in background ma restituisce risposta al client nell'applicazione Web ASP MVC

Ho provato tanti modi diversi ma l'interfaccia utente non risponde ancora immediatamente.

ho cercato BackgroundWorker ma non è che consente il thread principale di risposta al cliente fino alla sua trasformazione a farsi, anche ho provato:

Thread.QueueUserWorkItem(delegate { //method which performs stored procedure calls// 
}); 

Ancora non tornare risposta e HttpContext.Current non disponibile in thread in background.

Forse c'è un modo per avviare l'elaborazione in background, metterlo in pausa per lasciare che il thread principale restituisca la risposta al browser e quindi riprendere il thread in background per eseguire tutta l'elaborazione con le chiamate stored procedure?

Mi manca qualcosa?

Qualcuno potrebbe dare un'idea di come posso risolvere questo problema? Sarebbe molto apprezzato

+1

Vorrei sconsigliare di provare a mantenere qualcosa come il contesto HTTP. Ovviamente hai bisogno di qualcosa da questo, quindi passa tutto ciò che è nel tuo thread in background come stato del thread ed esegui l'elaborazione. Questo non è solo più semplice, ma definendo ciò di cui ha bisogno il tuo thread, è meglio definirne lo scopo. –

risposta

6

Cosa ho avuto e funziona nel mio caso. Non sono sicuro dell'efficienza, ma funziona perfettamente. Quindi, il codice che effettua chiamate a una stored procedure viene inserito in un thread separato, in modo che il thread principale sia terminato mentre l'elaborazione delle chiamate in background avviene su un thread separato e termina correttamente dopo un certo periodo di tempo. Allo stesso tempo, l'interfaccia utente è disponibile in modo che l'utente possa effettuare un'altra richiesta che verrà elaborata allo stesso modo. Ho provato tre richieste. Uno dopo l'altro si sovrappongono, il che significa che mentre la prima richiesta veniva elaborata sullo sfondo, ne presentai un'altra e un'altra ancora. L'UI ha risposto immediatamente e tutto il lavoro è stato fatto.

// ...main thread is working here 
    //put a call to stored procedure on a separate thread 
    Thread t = new Thread(()=> { 
     //call stored procedure which will run longer time since it calls another remote stored procedure and 
     //waits until it's done processing 
    }); 
    t.Start(); 

    // ...main thread continue to work here and finishes the request so it looks for user as the response is coming right away, all other stuff is being processed on that new thread so user even doesn't suspect 
+0

c'è l'errore "non può convertire implicitamente il tipo void in Thread" –

2

Citerò Stephan Clearys great article:

Quando si utilizza async sul lato server (ad esempio, con ApiController), allora si può trattare ogni richiesta tela come un'operazione asincrona. Ma quando si cede, si cede solo al pool di thread del server Web, non al client. HTTP consente solo una risposta singola, quindi la risposta può essere inviata solo quando la richiesta è completa.

Fondamentalmente, questo non aderisce al protocollo HTTP, dove ogni richiesta ha una sola risposta.

Questo può essere ottenuto utilizzando più chiamate al servizio ASP.NET, in cui una richiesta restituisce immediatamente un ID univoco, che il client può interrogare più volte per l'avanzamento. È possibile esaminare SignalR per assistenza con tale implementazione:

Che cos'è la funzione SignalR e "Real-time Web"? È la capacità di far sì che il codice lato server spinga il contenuto ai client connessi come accade, in tempo reale.

0

Se la risposta al client non dipende dal risultato del processo in background (cioè eseguire il processo in background e non hanno l'interfaccia utente in attesa di essa), allora si potrebbe utilizzare Revalee (uno strumento open-source) per eseguire l'attività in background.

L'interfaccia utente richiederà questo percorso ...

public class ForegroundController : Controller 
{ 
    public ActionResult InitiateBackgroundTask() 
    { 
    // The absolute URL that will be requested on the callback. 
    var callbackUri = new Uri("http://localhost/BackgroundTask/Callback"); 

    // The information that will be needed to initiate the background task. 
    object state = "Any object"; 

    this.CallbackNowAsync(callbackUri, state) 

    // ... your controller will now return a response to the browser 
    return View(); 
    } 
} 

lavoro di fondo sarà eseguito in questo controller ...

public class BackgroundTaskController : Controller 
{ 
    [AllowAnonymous] 
    [HttpPost] 
    [CallbackAction] 
    public ActionResult Callback(Guid callbackId, object state) 
    { 
    // Perform the background work 

    // ... insert your background task code here ... 

    // Return a status code back to the Revalee Service. 
    return new HttpStatusCodeResult(HttpStatusCode.OK); 
    } 
} 

Revalee Project Site

2

C'è part1 e part2 articolo di Dino Esposito delinea un modo per raggiungere il tuo polling utilizzando un timer lato client e azioni di controllo. In pratica, serializzi l'accesso a un metodo di controllo progressista che restituisce lo stato dell'attività e i dati di completamento. Tuttavia, potrebbe essere un po 'loquace se si stanno solo eseguendo uno o due processi di lunga durata.

Problemi correlati