2013-06-05 4 views
2

Je développe un site Web utilisant .NET MVC3. J'ai un contrôleur où je fais un téléchargement de fichier au client. Ce que j'aime faire est de supprimer le fichier après avoir téléchargé ce fichier. J'ai pensé que je peux utiliser ActionFilterAttribute. J'ai donc écrit la classe ci-dessous:ActionResultFilter page introuvable erreur

public class DeleteFileAfterDownloadFilter : ActionFilterAttribute 
{ 
    public override void OnResultExecuted(ResultExecutedContext filterContext) 
    { 
     string fileName = ((FileStreamResult)filterContext.Result).FileDownloadName; 
     File.Delete(fileName); 
     base.OnResultExecuted(filterContext); 
    } 
} 

Je suppose que j'ai 2 problèmes ici. Le premier est que quand je cours cette chose, il me donne l'erreur de ".../Company/DownloadVersion?versionID=2057" page n'a pas pu être trouvé. Quel est le moyen de le faire fonctionner?

Et le deuxième problème est que comme vous l'avez peut-être réalisé "((FileStreamResult)filterContext.Result).FileDownloadName" n'est probablement pas le chemin de fichier que je veux supprimer. Ce devrait être la variable locale "tempZipFile" dans le contrôleur. Mais je ne sais pas comment transmettre cette valeur à cet événement.

+0

merci pour les corrections, le rend plus lisible. –

+0

Et le PageNotFound est provoqué par le filtre (c.-à-d. Que le téléchargement est OK sans)? –

+0

Aucun téléchargement n'a lieu. –

Répondre

1

J'ai donné un spin à votre filtre et (après corrections) il produit une méchante erreur COM. C'est parce que la nature asynchrone de l'opération est: OnResultExecuted est votre dernière chance de faire quelque chose mais cela arrive quand la réponse (avec le nom de fichier mais pas le fichier lui-même) a été renvoyée au client. Lorsque le client (navigateur) lance alors le téléchargement, une erreur Not Found ou pire est produite. En d'autres termes, votre approche semble bien mais elle ne fonctionnera pas.

Quelques idées brutes pour une solution:

  • assurez-vous que vos fichiers côté serveur ont des noms uniques et un horodatage fiable
  • utiliser un processus d'arrière-plan pour les nettoyer périodiquement, ou
  • nettoyer vieux fichier à chaque fois que vous préparez un nouveau

J'ai changé votre filtre comme ceci:

public override void OnResultExecuted(ResultExecutedContext filterContext) 
    {    
     base.OnResultExecuted(filterContext); 

     var r = filterContext.Result as FilePathResult; // not FileContent   
     string fileName = 
      filterContext.RequestContext.HttpContext.Server.MapPath(r.FileName);    
     System.IO.File.Delete(fileName); 
    } 

Mise à jour:

Merci à this SO answer, ce qui suit devrait fonctionner:

public override void OnResultExecuted(ResultExecutedContext filterContext) 
    {    
     base.OnResultExecuted(filterContext); 

     var r = filterContext.Result as FilePathResult; // not FileContent   
     string fileName = 
      filterContext.RequestContext.HttpContext.Server.MapPath(r.FileName); 

     filterContext.HttpContext.Response.Flush(); 
     filterContext.HttpContext.Response.End(); 

     System.IO.File.Delete(fileName); 
    } 
+0

Merci, et si autour de la méthode File.Delete je vérifie si le fichier est occupé ou non? Si pendant l'envoi du fichier au client le fichier est occupé sur le serveur je suppose que mon approche fonctionnerait, sinon c'est toujours un problème de les nettoyer périodiquement car je ne saurais pas si le fichier est encore en cours Le fait d'attendre qu'un nouveau fichier ne soit pas téléchargé n'est pas une bonne approche car cela surchargerait mon serveur car les fichiers à télécharger peuvent être de l'ordre de 2-3 Go. Je ne veux pas stocker leur. –

+0

Ah, j'ai trouvé une réponse relavnt. Éditera. –

+0

Merci encore, je suppose que cette méthode de flush fait attendre que le téléchargement se termine, non? –