tags:

views:

294

answers:

2

Hello,

I'm trying to send a view that contains a html table as a downloadable file to the user, as an excel file.

I keep getting the error "Server cannot set content type after HTTP headers have been sent.". I can't figure out what's going wrong...

Here's some 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;
    }

While debugging, string "view" contains:

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

Any idea? I do about the exact same thing with a blob and that nicely returns a document to download.

+1  A: 

Did you use the RenderViewToString method from this post: http://stackoverflow.com/questions/483091/render-a-view-as-a-string?

If you did then there is a Response.Flush in that code which is sending the headers. Buffering is enabled by default but if you call Response.Flush then everything is sent down to the client. And then why you try to send the file with the updated headers, you get that error.

Jeff Widmer
Yeah that's the one I use! That seems to be the problem. Now, how do you solve it? :-)I'd like to keep using that method.
Thomas Stock
Not sure... It definitely does not feel correct that you need to call a Flush in RenderViewToString in order to get the string contents of a view. I wonder if there is some other way of writing the view to a stream directly?
Jeff Widmer
No idea.. I guess this is my punishment for using code I don't understand.
Thomas Stock
I spent a lot of time 6 months ago trying to take remove the Response.Flush() (I was using it to create email templates, then trying to redirect) but wasn't successful. I hope someone can solve it.
James S
I don't remember the exact solution but this post helped me in the right direction.. marking as answer
Thomas Stock
+2  A: 

You could get around this issue by putting this in the controller. It allows you to put HTML in a view, and then send it to the browser.

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

Sounds hacky? It is a little. I had the same problem you mentioned, and the question Jeff points to is also one of mine. :)

As mentioned in my comment, you should ensure that your view does not have the following:

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

None of this is needed, and may result in your page being rendered as HTML, rather than the Excel document being returned. So all you'll have rendered is the actual table tags and everything inside.

Dan Atkinson
does this work for you? All it does here is show the HTML in the browser
Thomas Stock
Sorry, I'll delete my last comment. I meant it DOES work! :) But, you could try putting the this.Response code inside the view. Either way, it should work.Also, you may want to ensure that the view (or most likely, the master) does not contain anything outside the table tags (html, head, body).
Dan Atkinson
Unfortunately, this won't work for me, where I need to render 20 or 30 views to strings (email templates). Any other ideas, no matter how hacky?
James S
Why won't it work? You can easily create a master page that has no content except for the <asp:ContentPlaceHolder ID="mainContentContainer" runat="server" />
Dan Atkinson