0

My code is below:

    [System.Web.Mvc.HttpPost]
    public ActionResult DownloaZipFile([FromBody] int id)
    {
        var result = _service.GetDocuments(id);
        var downloadFileName = $"Report{id}.zip";
        var downloadFilePath = Server.MapPath($"~/Uploads/TempZipDownload/{downloadFileName}");

        if (System.IO.File.Exists(downloadFilePath))
        {
            System.IO.File.Delete(downloadFilePath);
        }

        var zip = ZipFile.Open(downloadFilePath, ZipArchiveMode.Create);

        foreach (var file in result)
        {
            zip.CreateEntryFromFile(Server.MapPath(Path.Combine("~/Uploads/TempImageDownload/" + file.Filename)), file.Filename);
        }

        zip.Dispose();
        return File(downloadFilePath, "application/zip", downloadFileName);
    }

AngularJs code from component:

vm.downloadReport = function(id) {
            service.DownloadReport(id).then(function(response) {

                var file = new Blob([response.data],
                {
                    type: 'application/zip'
                });

                if (navigator.msSaveBlob) {
                    navigator.msSaveBlob(file);
                } else {
                    var fileUrl = URL.createObjectURL(file);
                    console.log(fileUrl);
                    var a = document.createElement('a');
                    a.href = fileUrl;
                    a.download = 'ReportDownload' + id + '.zip';
                    document.body.appendChild(a);
                    a.click();
                }
            });
        }

After all code its downloading zip file but when I am trying to open zip file its giving me error. Invalid zip file.

Please note I have used System.IO.Compression libraries to generate and download zip file.

Krutal Modi
  • 477
  • 9
  • 25
  • 1
    if you download the Zip directly (by visiting the action URL in your browser bar, not via your Javascript), does it work then? We need to narrow down the problem. – ADyson Apr 18 '18 at 09:11
  • Yes it works fine in that case. It downloads the file from where it is saved on server. – Krutal Modi Apr 18 '18 at 09:45
  • 1
    Ok so instead of all this convoluted code to download some content, generate a hyperlink and pretend to click it, why not just make your script do a window.location or window.open command to that URL, and then it will download normally. Downloading via ajax is not really a good solution in general, it's not meant to work that way – ADyson Apr 18 '18 at 09:54
  • 1
    Yes I agree your point of view and I fixed it like that only, what i did is I returned URL of that Zipped file as response.data and then created virtual hyperlink in javacript and clicked that hyperlink. So that fixed it. Thank you for your time and help. :) – Krutal Modi Apr 20 '18 at 10:02
  • you should add that as the answer, maybe with a little code snippet to explain. You are allowed to answer and accept your own question. Then others can find it (and potentially upvote it) in future – ADyson Apr 20 '18 at 10:06
  • Sure doing it :) – Krutal Modi Apr 20 '18 at 10:07

2 Answers2

1

I fixed this issue by doing following:

    [System.Web.Mvc.HttpPost]
    public ActionResult DownloaZipFile([FromBody] int id)
    {
        var result = _service.GetDocuments(id);
        var downloadFileName = $"Report{id}.zip";
        var downloadFilePath = Server.MapPath($"~/Uploads/TempZipDownload/{downloadFileName}");

        if (System.IO.File.Exists(downloadFilePath))
        {
            System.IO.File.Delete(downloadFilePath);
        }

        var zip = ZipFile.Open(downloadFilePath, ZipArchiveMode.Create);

        foreach (var file in result)
        {
            zip.CreateEntryFromFile(Server.MapPath(Path.Combine("~/Uploads/TempImageDownload/" + file.Filename)), file.Filename);
        }

        zip.Dispose();
        return Json($"/Uploads/TempZipDownload/{downloadFileName}");
    }

In the AngularJs code :

vm.downloadReport = function(id) {
            service.DownloadReport(id).then(function(response) {
                var a = document.createElement('a');
                a.href = response.data;
                a.download = 'ReportDownload';
                document.body.appendChild(a);
                a.click();
            });
        }

This will catch zipped file url in response.data and download it by javascript code. Hope this will helpful to others too.

Krutal Modi
  • 477
  • 9
  • 25
  • 2
    I think you can just do `window.location.href = response.data` instead of creating a dummy hyperlink. https://developer.mozilla.org/en-US/docs/Web/API/Location . You could also reduce the whole thing to a single HTTP request by using window.location.href to visit a single action URL (e.g. downloadZipFile) which creates the zip file and then sends it for download as a FileResult. Then you don't need the separate ajax call just to get the URL of the file. – ADyson Apr 20 '18 at 15:33
  • @ADyson you saved me. literally. – YTG Mar 25 '21 at 08:50
0

I think you can just do window.location.href = response.data instead of creating a dummy hyperlink. See https://developer.mozilla.org/en-US/docs/Web/API/Location for documentation.

You could also reduce the whole thing to a single HTTP request by using window.location.href to visit a single action URL (e.g. /downloadZipFile) which creates the ZIP file and then sends it for download as a FileResult immediately. You may even be able to create it in-memory without saving it to disk. Then you don't need the separate AJAX call just to get the URL of the file.

ADyson
  • 57,178
  • 14
  • 51
  • 63