Search code examples
javascriptjqueryasp.net-corehttpresponse

download file failed using response ASP.NET Core


I have the following code to download the file

jquery

 function DownloadExcel() {
        var laundrys = new Object();          

        $.ajax({
            type: 'POST',
            url: '@Url.Content("Laundry/DownloadExcel")',
            data: { laundry: laundrys},
            dataType: 'json',
            beforeSend: function () {
                $("#loadinggif").show();
            },
            success: function (result) {
                $("#loadinggif").hide();
                if (result.isuccess) {
                    GenerateFile(result);
                }
                else {
                    Swal.fire('Error Found', result.messageerror, 'error');
                }
            },
            error: function (result) {
                $("#loadinggif").hide();
                Swal.fire('Unknown Error', result, 'error');

            }
        });
    }

    function GenerateFile(result) {
        $.fileDownload('@Url.Content("Laundry/GenerateFiles")',
            {
                httpMethod: "POST",
                data: {
                    folder: result.folder,
                    filesname: result.filesname
                },
                successCallback: function (url) {
                    Swal.fire('Download Success', "", 'success');
                },
                failCallback: function (responseHtml, url) {
                    Swal.fire('Download Failed',responseHtml, 'error');
                }
            });
    }

and this is the code in my c# c#

public JsonResult DownloadExcel(Laundry laundry)
        {
            bool result = true;
            string MsgError = null;
            string Folder = null;
            string FileName = "GenerateFile-"+ DateTime.Now.ToString("yyyyMMdd_HHmmss").Replace("/", "-")+".xls";
            try
            {
                string startupPath = _webHostEnvironment.WebRootPath;
                Folder = startupPath + "\\template\\";
                string Path = Folder + "Template.xls";
                string NewPath = Folder + FileName;

                System.IO.File.Copy(Path, NewPath, true);

                HSSFWorkbook workBook;
                using (FileStream fs = new FileStream(NewPath, FileMode.Open, FileAccess.Read))
                {
                    workBook = new HSSFWorkbook(fs);
                }

               //mycode
              
                workBook.SetSheetName(0, "Report Laundry");
                using (FileStream fs = new FileStream(NewPath, FileMode.Create, FileAccess.Write))
                {
                    workBook.Write(fs);
                    fs.Close();
                }

            }
            catch(Exception e)
            {
                result = false;
                MsgError = "Error Exception: " + e.Message;
            }

            return Json(new { isuccess = result, messageerror = MsgError,folder = Folder, filesname = FileName,  });
        }

public ActionResult GenerateFiles(string folder, string filesname)
        {
            string Msg = "success";
            try
            {
                byte[] Data = System.IO.File.ReadAllBytes(folder + filesname);
                string contentType;
                new FileExtensionContentTypeProvider().TryGetContentType(filesname, out contentType);

                HttpContext.Response.Clear();
                HttpContext.Response.ContentType = contentType;
                HttpContext.Response.Headers.Add("Content-Length", Convert.ToString(Data.Length));
                HttpContext.Response.Headers.Add("Content-Disposition", string.Format("{0};FileName=\"{1}\"", "attachment", filesname));
                HttpContext.Response.Headers.Add("Set-Cookie", "fileDownload=true; path=/");
                HttpContext.Response.Body.WriteAsync(Data);
            }
            catch(Exception e)
            {
                Msg = "error Exception : "+e.Message;
            }

            System.IO.File.Delete(folder + filesname);

            return Json(Msg);
        }

when I use the following code, the download is successful but the file is not downloading with the error message failed network error. Is it caused by writing my response code incorrectly?


Solution

  • Your GenerateFiles method is trying to return two things in the same response - the content of the file, and a JSON blob. That won't work.

    You should also remove the folder parameter, since it poses a security risk. You're not validating it, so a hacker could instruct your method to send them any file from anywhere on your server. And you need to validate that the full path of the file you're returning is within the target folder.

    public ActionResult GenerateFiles(string filesname)
    {
        string startupPath = _webHostEnvironment.WebRootPath;
        string folder = System.IO.Path.Combine(startupPath, "template");
        string filePath = System.IO.Path.Combine(folder, filesname);
        
        if (!filePath.StartsWith(folder, StringComparison.OrdinalIgnoreCase))
        {
            // The file is not within the target folder.
            // Eg: The user requested "../../../../passwords";
            return NotFound();
        }
        
        if (!System.IO.File.Exists(filePath))
        {
            // The file does not exist.
            return NotFound();
        }
        
        if (!new FileExtensionContentTypeProvider().TryGetContentType(filesname, out string contentType))
        {
            // The file MIME type is not available.
            return NotFound();
        }
        
        string downloadFileName = System.IO.Path.GetFileName(filePath);
        byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
        System.IO.File.Delete(filePath);
        
        HttpContext.Response.Headers.Add("Set-Cookie", "fileDownload=true; path=/");
        return File(fileBytes, contentType, downloadFileName);
    }