Incorrect Content-Length causing File download resets in webpage

Our application generates an excel (by combining data from database with a static excel template file) and then streams the xlsx file back to our web application users.
This is the API used:
public void Save(HttpResponse response, string fileName, ContentDisposition contentDisposition, SaveOptions saveOptions);

This is how we use it:
wbook.Save(this.Response, wbookName, ContentDisposition.Attachment, new OoxmlSaveOptions());

The problem is that we are getting the following headers set by this API:
HeaderName="Content-Length", HeaderValue="1222734",
But right after the binary excel is streamed back, the following is seen in the HTTP stream:
BytesSent="1223165",

This mismatch is causing the load balancer to reset the connection as it is an RFC violation. This in turn errors out the file download on the user’s browsers. Please take a look at this urgent issue.

thanks,

@r_a_ven,

Aspose.Cells does save/export it by Response object, see the following code (similar is written behind the Workbook.Save overloaded method):
e.g
Sample code:

//..........
    //Send workbook to response/
    OoxmlSaveOptions xSaveOptions = new OoxmlSaveOptions(SaveFormat.Xlsx);

             MemoryStream tempStream = new MemoryStream();
            workbook.Save(tempStream, xSaveOptions);

             //set the position.
             tempStream.Position = 0;

             this.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            this.Current.Response.AddHeader("content-disposition", "attachment; filename=out1.xlsx" );
             Response.BinaryWrite(tempStream.ToArray());

Could you confirm the behavior by simply using Response object (with System.IO APIs) to export an Excel file to the client without using Aspose.Cells API. Do you see any difference (other than you described)? If so, give us more details and sample project (runnable), we will check it soon.

I created the workbook through Aspose APIs and exported it using Response object, System.IO API. It worked fine.

Below is the code:

            MemoryStream ms = new MemoryStream();
            wbook.Save(ms, SaveFormat.Xlsx);

            Response.Clear();
            Response.ClearHeaders();
            Response.ClearContent();
            Response.AddHeader("content-disposition", "attachment; filename=" + wbookName);
            Response.AddHeader("Content-Type", "application/Excel");
            Response.ContentType = "application/vnd.xls";

            byte[] bytes = ms.ToArray();
            Response.BinaryWrite(bytes);
            Response.End();

We were able to download the excel with the above code which wasn’t working with following Aspose Save method:
wbook.Save(this.Response, wbookName, ContentDisposition.Attachment, new OoxmlSaveOptions());

@animesh.g,

Could you add “Response.End();” after using the above line if it makes any difference. Also, please try using our latest version/fix v19.7.x.

Thanks. It worked after adding Resonse.End(); with Save method.

Have few questions -

  • How does it make a difference, with or without Resonse.End()?
  • How is it working for small workbooks without using Resonse.End() but fails for bigger workbooks i.e. more than 1 mb size? We were using HttpContext.Current.ApplicationInstance.CompleteRequest(); instead of Resonse.End() that also executes the EndRequest event and it works fine for small size of workbooks.
  • We are using v19.3.0.0. Is Resonse.End() already added with Save method in latest version?

@animesh.g,

Good to know that your issue is sorted out by adding the suggested line of code.

For your queries,

  1. Please note, without Response.End(), Response will continue to write some data about web page to the output streams.

  2. We do not know what happened to HttpContext.Current.ApplicationInstance.CompleteRequest(). Could you just remove all Aspose.Cells codes (even using the lines "MemoryStream ms = new MemoryStream();wbook.Save(ms, SaveFormat.Xlsx);"), just simply use System.IO APIs to read the file and then use Response object to write the file to check this issue.

  3. We do not add Response.End() in the latest versions/fixes too. We cannot close Response object because we do not know whether there is any job to be done after exporting file. The user should manually add it as we think.

I had the same issue today trying to download a synamic created excel file in a generic handler

This did not work:

wb.Save(context.Response, “filename.xlsx”, ContentDisposition.Attachment, new OoxmlSaveOptions());

This did:

            MemoryStream ms = new MemoryStream();
            wb.Save(ms, new OoxmlSaveOptions());
            byte[] data = ms.ToArray();
            context.Response.ContentType = $"application/xlsx";
            context.Response.AddHeader("Content-Disposition", $"attachment; filename=\"filename.xlsx\"");
            context.Response.AddHeader("Content-Length", data.ToString());
            context.Response.BinaryWrite(data);

@kwhite,

Please try to add “Response.End();” after using the above line if it makes any difference.

i did try that, it didnt work. it always set the content-length to 0

manually converting to a byte array and setting the content-length to the length of the array was the only thing that worked.

side note: this was specifically to address the issue with chrome. it worked fine in the old IE. in chrome, we would get the “Failed - Network Error” message. but resume download would work. using fiddler i was able to see that the difference was the content-length

@kwhite,

Please create a separate VS.NET sample project (runnable), zip the application and post us to reproduce the issue on our end, we will check it soon. Please exclude Aspose.Cells.Dll to minimize the size of the project. Also, give us complete error trace displayed in the browser (Google chrome).

PS. please try our latest version, i.e., Aspose.Cells for .NET v21.6 if you are not already using it.