2009-08-24 13 views
8

Sto utilizzando ASP.NET MVC e ho un processo in esecuzione lungo. Nello specifico sto generando un PDF di grandi dimensioni che l'utente può scaricare.Processo in esecuzione prolungata che restituirà un file

Capisco il concetto di base:

  1. metodo d'azione viene chiamato
  2. Nuovo thread ha iniziato a generare processo
  3. ritorno una visualizzazione che indica all'utente il (pdf) viene generato
  4. Usa AJAX per chiamare il server e chiedere progressi
  5. Una volta terminato, presentare il file all'utente per il download.

Le parti non capiscono fino in fondo sono:

  • La gestione del filo attraverso AJAX separata chiamate. Avrò probabilmente bisogno di un modo per trovare il thread in esecuzione e richiedere uno stato. C'è un contesto statico in cui posso mantenere un riferimento al thread? Sono a conoscenza della cache dei dati in HttpContext.Application, sarebbe adatto per questo?
  • E come presentare il file completato. Devo creare un file temporaneo e presentare un collegamento per il download? Oppure posso effettuare una chiamata AJAX finale che restituisce il file?
+0

Ottima domanda ... bloccato nella stessa situazione! –

risposta

6

Il Cashe è molto adatto per questo. Solo una cosa è assicurarsi che l'elemento memorizzato nella cache non venga mai rimosso mentre il processo è in esecuzione (puoi usare ItemPriority.NotRemovable per quello).

È possibile salvare il file su disco nella cartella Temp oppure è possibile tenerlo nella cache per un po 'di tempo (dipende).
Personalmente non mi piace inquinare il disco rigido con i file, quindi manterrò il file nella cache (con MediumPriority durante un paio di minuti). Ma il file è di grandi dimensioni e può essere generato, spesso, si consideri invece l'utilizzo del Database del file system.

Sul client, quando gli ultimi richiesta restituisce Ajax finiscono (può apparire come {progresso: "100%", resultUrl: "http://your.url/Where/ToGet/TheFile.aspx?file=GUID-OR-CACHE-KEY"}) è possibile reindirizzare il browser a un URL previsto.
A sua volta, renderà quel file come risultato binario.

reindirizzamento client può essere fatto utilizzando Javascript in questo modo:

location.href = response.resultUrl; 

BTW, come si fa a generare PDF? NFOP?

+0

Grazie per la risposta. Ho intenzione di fare una prova a breve quindi ti farò sapere come vado avanti. Al momento non ho i mezzi per generare il PDF vero :( – jeef3

+0

Un'altra cosa che ho dimenticato di menzionare C'è AsynController nel sito MVP CodePlex di ASP.NET.Potrebbe essere utile per voi. Penso che sia astratto dal threading compiti –

+0

Oh wow, interessante, dovrò esaminarlo. – jeef3

7

Funziona!

Ecco che cosa ho fatto:

Fase 1 & 2 - Azione Metodo viene chiamato, a lungo in esecuzione thread viene avviato

Quando il mio metodo di azione viene chiamato, genera un ID univoco. Quindi istanziare un'istanza della mia classe PdfGenerator, creare un nuovo thread che chiama PdfGenerator.Generate e avviarlo.

public class PdfGenerator 
{ 
    public string State; 
    public byte[] Data; 

    public void Generate() 
    { 
     // Generate PDF/Long running process 
     // Should update State as it goes 
     // ... 
     // Once finished, Data is populated with the binary byte[] 
    } 
} 

Una volta che il filo è iniziata (o prima) l'istanza generatore viene memorizzato nella cache:

HttpContext.Cache[guid] = generator; 

Allego inoltre il GUID al Viewdata in modo che possa essere riferimento nella mia vista script.

Fase 3 & 4 - Display e vista

Ora che il thread è in esecuzione e la generazione di PDF ha iniziato aggiornamento di stato/di avanzamento, posso visualizzare mio punto di vista il progresso script. Usando di $.getJSON sono in grado di eseguire il polling un'azione separata per trovare lo stato della generazione jQuery:

[OutputCache(Duration = 0, VaryByName = "none", NoStore = true)] 
public JsonResult CheckPdfGenerationStatus(string guid) 
{ 
    // Get the generator from cache 
    var generator = HttpContext.Cache[guid] as PdfGenerator; 

    if (generator == null) 
     return Json(null); 
    else 
     return Json(generator.State); 
} 

Il mio script vista interpreta il JSON e visualizza le informazioni di avanzamento appropriata.

Fase 5 - lima Presente all'utente

Una volta che la generazione è stata completata, lo stato di generatori è impostato di conseguenza e quando jQuery riceve queste informazioni, si può sia mettere a disposizione un link, o direttamente inviare il file utilizzando javascripts location.href.

Il metodo d'azione che imposta e restituisce il file viene semplicemente il generatore di fuori della cache e restituisce il byte allegato []

public ContentResult DownloadPdf(string guid) 
{ 
    var generator = HttpContext.Cache[guid] as PdfGenerator; 

    if (generator == null) 
     return Content("Error"); 

    if (generator.State == "Completed") 
    { 
     return Content(generator.Data); 
    } 
    else 
    { 
     return Content("Not finished yet"); 
    } 
} 

Il mio mio lavoro effettivo devo stato più dettagliate come inizializzato , In esecuzione e completato. Così come una percentuale di progresso (espressa come decimale, 1.0 completa).

Quindi sì, spero che aiuti chiunque altro a provare a fare qualcosa di simile.

Problemi correlati