Generating an excel file with EPPlus is failing

23,104

Solution 1

All you need to do is reset the stream position. stream.Position = 0;

You shouldn't write directly to the Response, it's not the MVC way. It doesn't follow the correct MVC pipeline and it tightly couples your controller action code to the Response object.

When you add a file name as the 3rd parameter in File(), MVC automatically adds the correct Content-Disposition header... so you shouldn't need to add it manually.

The short of it is, this is what you want:

public ActionResult Index()
{
    using (ExcelPackage package = new ExcelPackage())
    {
        // I populate the worksheet here.  I'm 90% sure this is fine
        // because the stream file size changes based on what I pass to it.

        var stream = new MemoryStream();
        package.SaveAs(stream);

        string fileName = "myfilename.xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        stream.Position = 0;
        return File(stream, contentType, fileName);
    }
}

Solution 2

Your code doesn't show stream being written to the HttpResponse - presumably being done in the File method which you haven't posted.

One way that does work is the following:

Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader(
            "content-disposition", String.Format(CultureInfo.InvariantCulture, "attachment; filename={0}", fileName));
Response.BinaryWrite(package.GetAsByteArray());
Response.End();

Solution 3

Similar to Joe's answer, I still had to call Response.ClearHeaders():

   protected void btnDownload_Click(object sender, EventArgs e)
   {

       ExcelPackage pck = new ExcelPackage();
       var ws = pck.Workbook.Worksheets.Add("Sample2");

       ws.Cells["A1"].Value = "Sample 2";
       ws.Cells["A1"].Style.Font.Bold = true;
       var shape = ws.Drawings.AddShape("Shape1", eShapeStyle.Rect);
       shape.SetPosition(50, 200);
       shape.SetSize(200, 100);
       shape.Text = "Sample 2 outputs the sheet using the Response.BinaryWrite method";
       Response.Clear();    
       Response.ClearHeaders();
       Response.BinaryWrite(pck.GetAsByteArray());
       Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
       Response.AddHeader("content-disposition", "attachment;  filename=Sample2.xlsx");
       Response.End();
  }
Share:
23,104
Matt Grande
Author by

Matt Grande

Matt Grande is a software developer from Hamilton, ON. He works in C# and Ruby on Rails. He is overweight and has bad hair.

Updated on February 11, 2020

Comments

  • Matt Grande
    Matt Grande over 4 years

    When I try to generate an Excel file using EPPlus, Excel give me the following error message:

    Excel cannot open the file 'myfilename.xlsx' because the file format or file extension is not valid. Verify the the file has not been corrupted and that the file extension matches the format of the file.

    Here's my code:

    public ActionResult Index()
    {
        using (ExcelPackage package = new ExcelPackage())
        {
            // I populate the worksheet here.  I'm 90% sure this is fine
            // because the stream file size changes based on what I pass to it.
    
            var stream = new MemoryStream();
            package.SaveAs(stream);
    
            string fileName = "myfilename.xlsx";
            string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    
            var cd = new System.Net.Mime.ContentDisposition
            {
                Inline = false,
                FileName = fileName
            };
            Response.AppendHeader("Content-Disposition", cd.ToString());
            return File(stream, contentType, fileName);
        }
    }
    

    Any idea what I'm doing wrong?

  • Matt Grande
    Matt Grande about 12 years
    The File method is part of ASP.Net MVC. I'll try this way!
  • Matt Grande
    Matt Grande about 12 years
    Strange, it now says "Excel found unreadable content in 'myfilename.xlsx'. Do you want to recover the contents of this workbook? If you trust the source of this workbook, click Yes." If I click Yes, it seems to work, but I have no idea what's giving that error.
  • Joe
    Joe about 12 years
    I have seen that error message before, IIRC it happened when Response.Clear() was omitted. Another possibility is that an EPPlus bug results in invalid data in the file. You can test which it is by saving the file on the server, and seeing if you get the same error when opening it on the server.
  • Joe
    Joe about 12 years
    Also when using the File method, you may need to first position your MemoryStream to the start of the stream (stream.Position = 0).
  • Matt Grande
    Matt Grande about 12 years
    Ahh, the "Excel found unreadable content" was my fault. I was trying to set a width on Column 0.
  • Charlino
    Charlino over 11 years
    -1 this isn't the way you should do it... it's not the MVC way and it tightly couples your code to the response object. All you need to do is reset the stream position.
  • Shawn
    Shawn over 10 years
    So question about this, I am using a similar method although I am currently returning a FileStreamResponse instead of a file object. The problem I am running into though is that if the user makes more than one request while the first file is being build, they all seem to get locked up and the saveas method never completes. Have you ran into this with EPPlus?
  • Christian Doulos
    Christian Doulos about 3 years
    Can yo post the ajax success method that handles this return?