2009-08-06 11 views
1

J'essaie d'envoyer une vue qui contient une table html comme un fichier téléchargeable à l'utilisateur, comme un fichier Excel.Servir une vue en tant que fichier dans asp.net mvc

Je reçois toujours l'erreur "Le serveur ne peut pas définir le type de contenu après que les en-têtes HTTP ont été envoyés.". Je ne peux pas comprendre ce qui se passe mal ...

Voici quelques code:

Excel.aspx:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> 
<html> 
<head runat="server"> 
    <title>Excel</title> 
</head> 
<body> 
.... 
</body> 
</html> 

ControllerAction:

public FileResult Excel() 
    { 
     string view = RenderViewToString(this.ControllerContext, "~/Views/Shared/Excel.aspx", null, this.ViewData, this.TempData); 

     MemoryStream stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(view)); 

     string mimetype = RainbowsDotNet.FileHandling.MimeType.GetMimetypeFromExtension(".xls"); 

     FileStreamResult filestreamresult = new FileStreamResult(stream, mimetype); 
     filestreamresult.FileDownloadName = "Employees_{0}.xls".FormatWith(DateTime.Now.ToString("ddMMyyyy_HHmmss")); 

     return filestreamresult; 
    } 

Bien que le débogage, la chaîne « vue "contient:

"\r\n<html>\r\n<body>............................" 

Une idée? Je fais à peu près la même chose avec un blob et ça retourne bien un document à télécharger.

+0

Je sais que c'est évident, mais vos en-têtes ont déjà été envoyés au client, vous devez donc savoir pourquoi. Qu'est-ce qui déclenche que les en-têtes ont déjà été envoyés. Vous n'avez peut-être pas activé la mise en mémoire tampon? Etes-vous volontairement désactivant la mise en mémoire tampon ailleurs? –

+0

votre "vue" des données est un YSOD (Yellow Screen Of Death), je commencerais là – mxmissile

+0

hmm, je n'ai pas touché le tampon, mais quand même. Je fais exactement la même chose que dans un autre contrôleur où je retourne aussi des documents et cela fonctionne bien là ... juste un FileResult qui renvoie un FileStreamResult .. –

Répondre

1

Avez-vous utilisé la méthode RenderViewToString de cet article: Render a view as a string?

Si vous l'avez fait, il y a un Response.Flush dans le code qui envoie les en-têtes. La mise en mémoire tampon est activée par défaut, mais si vous appelez Response.Flush, tout est envoyé au client. Et puis pourquoi vous essayez d'envoyer le fichier avec les en-têtes mis à jour, vous obtenez cette erreur.

+0

Ouais c'est celui que j'utilise! Cela semble être le problème. Maintenant, comment le résolvez-vous? :-) Je voudrais continuer à utiliser cette méthode. –

+0

Vous ne savez pas ... Il ne semble pas correct d'appeler un Flush dans RenderViewToString pour obtenir le contenu d'une vue. Je me demande s'il existe une autre façon d'écrire la vue directement à un flux? –

+0

Aucune idée .. Je suppose que c'est ma punition pour l'utilisation du code que je ne comprends pas. –

4

Vous pourriez contourner ce problème en mettant cela dans le contrôleur. Il vous permet de mettre du code HTML dans une vue, puis de l'envoyer au navigateur.

public ActionResult Excel() 
{ 
    this.Response.AddHeader("Content-Disposition", "Employees_{0}.xls".FormatWith(DateTime.Now.ToString("ddMMyyyy_HHmmss"))); 
    this.Response.ContentType = "application/vnd.ms-excel"; 
    //Do model stuff 
    Model model = new Model(); 
    return View(model); 
} 

Semble-t-il hacky? C'est un peu. J'ai eu le même problème que vous avez mentionné, et la question à laquelle Jeff fait allusion est aussi l'une des miennes. :)

Comme mentionné dans mon commentaire, vous devez vous assurer que votre point de vue n'a pas les éléments suivants:

<html> 
    <head> 
    ... 
    </head> 
    <body> 
    </body> 
</html> 

Rien de tout cela est nécessaire, et peut entraîner votre page en cours de rendu HTML, plutôt que le document Excel renvoyé. Donc, tout ce que vous aurez rendu, ce sont les étiquettes de la table et tout ce qu'il y a dedans.

+0

cela fonctionne pour vous? Tout ce qu'il fait ici est afficher le code HTML dans le navigateur –

+0

Désolé, je vais supprimer mon dernier commentaire. Je voulais dire que ça marche! :) Mais, vous pouvez essayer de mettre le code this.Response à l'intérieur de la vue. De toute façon, ça devrait marcher. En outre, vous pouvez vous assurer que la vue (ou le plus probable, le maître) ne contient rien en dehors des balises de table (html, head, body). –

+0

Malheureusement, cela ne fonctionnera pas pour moi, où j'ai besoin de rendre 20 ou 30 vues aux chaînes (modèles d'email). D'autres idées, peu importe comment hacky? –

Questions connexes