3

I am building a FileResult method which is supposed to return an excel file as a result. Currently the method looks like this:

public ActionResult GetExcelFile(int id)
    {
        var entityPermission = AuthenticationManager.GetEntityPermission(PermissionEntity.Events, PermissionLevel.AllRecords);
        if (entityPermission == null || !entityPermission.AllowRead)
            return Json(new RequestResult(RequestCode.Unauthorized), JsonRequestBehavior.AllowGet);

        try
        {
            using (var serviceManager = new ServiceManager())
            {
                // Get object model
                var firstTableObj = serviceManager.GetDataForExcel(id);
                StringBuilder sb = new StringBuilder();
                sb.Append("<table border=`" + "1px" + "`b>");
                sb.Append("<tr>");
                // ... appending other strings and data
                sb.Append("</table>");

                // Return FileResult
                byte[] byteArray = Encoding.UTF8.GetBytes(sb.ToString());
                return File(new MemoryStream(byteArray, 0, byteArray.Length), "application/octet-stream", $"{firstTableObj.CurrentDate}.xlsx");                   
            }
        }
        catch (Exception ex)
        {
            return Json(new RequestResult(RequestCode.Server_Failure, ex.Message), JsonRequestBehavior.AllowGet);
        }

Currently, when I send a request from Angular 2+ frontend, the request is being processed and returned, this is some of the header data:

Content-Disposition:attachment; filename=12.11.2017.xlsx, Content-Length:617, Content-Type:application/octet-stream

However, the file is not being downloaded, the response body is just the html template in string format. What am I missing? I have seen some examples of returning excel files as a FileResult in MVC and they are not much different from mine. Changing the MIME to 'application/vnd.ms-excel' didn't help either. Also, as far as I am aware, there is no need to implement any file download logic in the client, it should work as is, that is a response from the server. Will appreciate any hints on the subject.

P.S: I know that in general I should not load an entire file into memory, but this is currently for testing purposes (I know an approximate limit to returned file sizes) and will most surely be changed in the future development.

1
  • 1
    You are returning HTML, not XLSX. Commented Nov 12, 2017 at 15:28

2 Answers 2

1

You are not saving an xlsx file. You are saving an html file with xlsx extension.

You probably adjusted a sample found on the internet, but the initial extension was xls.

An html file with xls extension is not an Excel file either, but MS Excel knows to render the html file and displays the file into the spreadsheet. Still, with the recently MS Excel version a warning is raised that is an invalid file format.

If you need to save xlsx files, you need to search for an Excel library like OpenXML from Microsoft, EPPlus open source or EasyXLS commercial with 30-days trial.

Sign up to request clarification or add additional context in comments.

Comments

1

You should change

public ActionResult GetExcelFile(int id)

To

public FileResult GetExcelFile(int id)

And of course you can't handle Json response for FileResult. It should be like that;

public FileResult GetExcelFile(int id)
        {
            var entityPermission = AuthenticationManager.GetEntityPermission(PermissionEntity.Events, PermissionLevel.AllRecords);
            if (entityPermission == null || !entityPermission.AllowRead)
                //return Json(new RequestResult(RequestCode.Unauthorized), JsonRequestBehavior.AllowGet); 
                //Do something except returning Json response

            try
            {
                using (var serviceManager = new ServiceManager())
                {
                    // Get object model
                    var firstTableObj = serviceManager.GetDataForExcel(id);
                    StringBuilder sb = new StringBuilder();
                    sb.Append("<table border=`" + "1px" + "`b>");
                    sb.Append("<tr>");
                    // ... appending other strings and data
                    sb.Append("</table>");

                    // Return FileResult
                    byte[] byteArray = Encoding.UTF8.GetBytes(sb.ToString());
                    return File(new MemoryStream(byteArray, 0, byteArray.Length), "application/octet-stream", $"{firstTableObj.CurrentDate}.xlsx");                   
                }
            }
            catch (Exception ex)
            {
                //Do something except returning Json response
            }
}

2 Comments

No, FileResult derives from ActionResult. Both are fine as return type.
My controller was extending ApiController (not Controller); therefore my controller *did not have the File(...) method. I used an approach like this instead

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.