2009-08-24 6 views
8

J'utilise ASP.NET MVC et j'ai un long processus d'exécution. Plus précisément, je génère un fichier PDF volumineux que l'utilisateur doit télécharger.Processus en cours d'exécution qui retournera un fichier

Je comprends le concept de base:

méthode
  1. d'action est appelée
  2. Nouveau fil a commencé à générer des processus
  3. Retour une vue qui indique à l'utilisateur le (pdf) est généré
  4. Utilisation AJAX pour appeler le serveur et demander la progression
  5. Une fois terminé, présentez le fichier à l'utilisateur pour le téléchargement.

Les pièces que je ne comprends pas bien sont:

  • La gestion du fil à travers les appels AJAX séparés. J'aurai peut-être besoin d'un moyen de trouver le fil conducteur et de demander un statut. Y at-il un contexte statique que je peux garder une référence au fil de discussion? Je suis au courant de la mise en cache des données dans HttpContext.Application, serait-ce approprié pour cela?
  • Et comment présenter le fichier complété. Est-ce que je crée un fichier temporaire et présente un lien de téléchargement? Ou puis-je effectuer un appel AJAX final qui renvoie le fichier?
+0

Excellente question ... coincé dans la même situation! –

Répondre

6

Le Cashe est très bien adapté pour cela. Une seule chose est de s'assurer que l'élément mis en cache n'est jamais supprimé pendant que le processus est en cours d'exécution (Vous pouvez utiliser ItemPriority.NotRemovable pour cela).

Vous pouvez enregistrer le fichier sur le disque dans le dossier temporaire ou vous pouvez le garder dans le cache pendant un certain temps (cela dépend).
Personnellement, je ne veux pas polluer le disque dur avec des fichiers afin que je garde le fichier en cache (avec MediumPriority pendant quelques minutes). Mais du fichier est grand et peut être généré souvent envisager d'utiliser la base de données du système de fichiers à la place.

Sur le client, lorsque le dernier retourne requête Ajax résultat (peut ressembler {progrès: "100%", resultUrl: "http://your.url/Where/ToGet/TheFile.aspx?file=GUID-OR-CACHE-KEY"}) vous pouvez rediriger le navigateur vers une URL fournie.
À son tour, rendra ce fichier en tant que résultat binaire.

redirect client peut être fait en utilisant Javascript comme ceci:

location.href = response.resultUrl; 

BTW, comment voulez-vous générer PDF? NFOP?

+0

Merci pour la réponse. Je vais essayer dans un court laps de temps donc je vous ferai savoir comment je vais. Pour l'instant, je n'ai aucun moyen de générer le PDF réel :( – jeef3

+0

Une autre chose que j'ai oublié de mentionner: AsynController sur le site ASP.NET MVC CodePlex, qui pourrait vous être utile. tâches –

+0

Oh wow, intéressant, devra se pencher sur cela. – jeef3

7

Cela fonctionne!

Voici ce que je l'ai fait:

Étape 1 & 2 - Méthode d'action est appelée, long fil en cours d'exécution est lancé

Lorsque ma méthode d'action est appelée, il génère un identifiant unique. Je instancie alors une instance de ma classe PdfGenerator, crée un nouveau thread qui appelle PdfGenerator.Generate et le démarre.

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[] 
    } 
} 

Une fois que le fil a commencé (ou avant de commencer) l'instance du générateur est stocké dans le cache:

HttpContext.Cache[guid] = generator; 

Je joins aussi le Guid au ViewData afin qu'il puisse être fait référence à mon avis scénario.

Étape 3 & 4 - Affichage et mise à jour d'état/vue progrès

Maintenant que le fil est en cours d'exécution et la génération de PDF a commencé, je peux afficher mon script de vue de progrès. En utilisant jQuery de $.getJSON Je suis en mesure de sondage une action distincte pour connaître l'état de la génération:

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

Mon script de vue interprète JSON et affiche les informations de progrès appropriés.

Étape 5 - Présenter le fichier à l'utilisateur

Une fois la génération terminée, l'état des générateurs est réglé en conséquence et quand jQuery reçoit ces informations, il peut soit mettre à la disposition d'un lien, ou envoyer directement le fichier en utilisant javascripts location.href.

La méthode d'action qui met en place et retourne le fichier est tout simplement le générateur du cache et renvoie l'octet joint []

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

Mon mon travail réel que j'ai état plus détaillées telles que Initialisé , En cours d'exécution et terminé. Ainsi qu'un pourcentage de progression (exprimé en décimal, 1.0 étant complet).

Alors ouais, espérons que cela aide quelqu'un d'autre à essayer de faire quelque chose de similaire.

Questions connexes