2009-08-24 12 views
8

Estoy utilizando ASP.NET MVC y tengo un proceso de ejecución prolongado. Específicamente estoy generando un PDF grande para que el usuario lo descargue.Proceso de ejecución larga que devolverá un archivo

entiendo el concepto básico:

  1. método de acción es llamado
  2. Nuevo tema comenzó a generar proceso
  3. Volver a View que le indica al usuario la (pdf) se está generando
  4. Uso AJAX para llamar al servidor y solicitar progreso
  5. Una vez finalizado, presente el archivo al usuario para su descarga.

Las partes que no entiendo totalmente son:

  • La gestión de la rosca a través separada llamadas AJAX. Posiblemente necesite alguna forma de encontrar el hilo en ejecución y solicitar un estado. ¿Hay un contexto estático en el que pueda mantener una referencia al hilo? Estoy al tanto del almacenamiento en caché de datos en HttpContext.Application, ¿sería adecuado para esto?
  • Y cómo presentar el archivo completo. ¿Creo un archivo temporal y presento un enlace de descarga? ¿O puedo hacer una llamada AJAX final que devuelve el archivo?
+0

Excelente pregunta ... atrapado en la misma situación! –

Respuesta

6

El Cashe es muy adecuado para eso. Solo una cosa es asegurarse de que el elemento en caché nunca se elimine mientras se está ejecutando el proceso (puede usar ItemPriority.NotRemovable para eso).

Puede guardar el archivo en el disco en la carpeta temporal o puede guardarlo en la memoria caché durante un tiempo (depende).
Personalmente, no quiero contaminar el disco duro con archivos, así que mantendría el archivo en caché (con MediumPriority durante unos minutos). Pero si el archivo es grande y se puede generar, a menudo considere utilizar la base de datos del sistema de archivos.

En el cliente, cuando la última solicitud Ajax vuelve resultado (puede parecerse {progreso: "100%", resultUrl: "http://your.url/Where/ToGet/TheFile.aspx?file=GUID-OR-CACHE-KEY"}) puede redirigir el navegador a una dirección URL proporcionada.
A su vez, representará ese archivo como resultado binario.

redirección de cliente se puede hacer usando Javascript así:

location.href = response.resultUrl; 

Por cierto, ¿Cómo se genera PDF? NFOP?

+0

Gracias por la respuesta. Voy a intentarlo en breve para que sepas cómo me llevo. Por el momento no tengo medios para generar el PDF real :( – jeef3

+0

Otra cosa que olvidé mencionar. Hay AsynController en el sitio ASP.NET MVC CodePlex. Puede ser útil para usted. Creo que se abstrae del subprocesamiento tareas. –

+0

Oh, vaya, interesante, tendremos que investigar eso. – jeef3

7

¡Funciona!

Esto es lo que he hecho:

& Paso 1 2 - Método de Acción se llama, de larga duración hilo se inicia

Cuando mi método de acción es llamado, se genera un identificador único. A continuación, instalo una instancia de mi clase PdfGenerator, creo un nuevo hilo que llame al PdfGenerator.Generate y lo inicie.

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 vez que el mensaje ha comenzado (o antes de empezar) la instancia del generador se almacena en la memoria caché:

HttpContext.Cache[guid] = generator; 

también hay que adjuntar el GUID a la ViewData de modo que pueda ser referencia en mi opinión guión.

Paso 3 & 4 - Visualización y actualización de estado/progreso vista

Ahora que el hilo se está ejecutando y la generación de PDF ha comenzado, puedo mostrar mi punto de vista el progreso de la escritura. El uso de $.getJSON soy capaz de sondear una acción separada para encontrar el estado de la generación de 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); 
} 

Mi script de vista interpreta el JSON y muestra la información de progreso adecuado.

Paso 5 - archivo actual de usuario

Una vez que se ha completado la generación, el estado generadoras se fija en consecuencia y cuando jQuery recibe esta información, o bien puede hacer un enlace disponible, o directamente enviar el archivo usando javascripts location.href.

el método de acción que establece y devuelve el archivo, simplemente se pone el generador fuera de la caché y devuelve el byte adjunto []

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"); 
    } 
} 

Mi mi trabajo real tengo estado más detallada, como inicializado , Corriendo y Completado. Además de un porcentaje de progreso (expresado como un decimal, 1.0 está completo).

Así que sí, espero que ayude a alguien más a tratar de hacer algo similar.

Cuestiones relacionadas