3

I have a C# backend generating a zip file in memory (with System.IO.Compression) and sending it to my front end. If I download the zip file before sending it, it is working well and is in ANSI encoding (found on notepad++).

This is how I return my file currently, I have tried many different ways to do it, such as simply returning a file without headers, but right now it looks like this :

[HttpPost]
[Route("GetUserWorkContext")]
public async Task<IActionResult> GetUserWorkContext([FromBody] GetUserWorkContextRequest request, [FromServices] IExportManager exportManager)
{
    var zipStream = await exportManager.GetUserWorkContext(userId, request.IncludeArchived);
    HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename = test.zip; charset=Windows-1252");
    HttpContext.Response.Headers.Add("Content-Length", zipStream.ToArray().Length.ToString());
    return File(zipStream.ToArray(), "application/octet-stream");
}

It seems that no matter how I download the file with Javascript (front-end), it is saved with utf8 encoding (found with notepad++ again). I tried using js-file-download ( https://www.npmjs.com/package/js-file-download ) or creating blobs, but anything I end up downloading is encoded in utf8.

How should I go about downloading this file in Javascript without corrupting the archive ?

Here is my current attempt in Javascript, using a piece of code I found here (JavaScript blob filename without link) to download the file :

function getUserWorkContext({ includeArchived }) {
    return new Promise(function () {
        Axios.post('/api/Export/GetUserWorkContext', {includeArchived})
            .then((response) => {
                if(response.data){
                    var blobObject = new Blob([response.data], {type: 'application/zip;charset=Windows-1252'});
                    downloadFile(blobObject, "test.zip");
                }
            })
}

function downloadFile(file, fileName) {
    if (navigator.msSaveBlob) { // For ie and Edge
        return navigator.msSaveBlob(file, fileName);
    }
    else {
        let link = document.createElement('a');
        link.href = window.URL.createObjectURL(file);
        link.download = fileName;
        document.body.appendChild(link);
        link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
        link.remove();
        window.URL.revokeObjectURL(link.href);
    }
}

Note : the actual zip is 3,747KB where as the download zip from Javascript is always much bigger, in this case : 6,917KB.

barbo
  • 33
  • 3
  • 2
    Have you tried to remove the headers Content-Disposition and Content-Length? They appear redundant to me... – Eduard Keilholz Oct 29 '20 at 15:58
  • @nikneem Yes I have, I tried returning return File(zipStream.ToArray(), "application/octet-stream"); and return File(zipStream.ToArray(), "application/octet-stream", "test.zip"); without setting headers, both of which didn't work – barbo Oct 29 '20 at 16:00
  • I believe, you don't need to convert your ``zipStream.ToArray()``. It works well with the stream ``File(zipStream, "application/octet-stream", "test.zip");`` – Tolbxela Oct 29 '20 at 16:29
  • Good idea @Tolbxela, but it doesn't seem to change the outcome. – barbo Oct 29 '20 at 16:49
  • 1
    @barbo please check my updated answer. – Tolbxela Oct 29 '20 at 17:14

1 Answers1

2

This is a problem with axios:

I guess, you should use blob or arraybuffer as responseType for axios.

{ responseType: 'blob' }

// responseType indicates the type of data that the server will respond with // options are: 'arraybuffer', 'document', 'json', 'text', 'stream' // browser only: 'blob'

responseType: 'json' // default

Check this answer: https://stackoverflow.com/a/60461828/2487565

=== 8< ======================= previous version ======================= 8< ===

Your Content-Disposition header is wrong. There is no charset parameter for Content-Disposition header.

Check the docs: MDN HTTP Content-Disposition

That's why your file is still sent in UTF-8, since your charset parameter has no effect.

To use UTF-8:

Delete both Content- headers from C# and the charset parameter from JavaScript

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

If you really need to use Windows-1252, you can try to set it with the content type parameter.

 return File(zipStream.ToArray(), "application/octet-stream;charset=Windows-1252");

Check this also: Charset Encoding in ASP.NET Response

By the way, UTF-8 is the preferred charset encoding: W3 QA choosing encodings

And, yes @nikneem, there is no need in the Content-Disposition and Content-Length headers. They will be generated automatically.

Tolbxela
  • 4,767
  • 3
  • 21
  • 42
  • 1
    Hi! The content type doesn't change the result. I think the issue lies more in the way the file is downloaded in the front end, as it always defaults to utf8. The response.data that is used to create the blob is just a string, there is no info on the content type used there... – barbo Oct 29 '20 at 16:42
  • I would like to use UTF8, but I have not found a way to create an archive encoded in UTF8. This would indeed simplify things a lot – barbo Oct 29 '20 at 16:42
  • Also, the reason I was trying to change the content-disposition is because in the response headers, I can see this : Content-Disposition: attachment; filename=test.zip; filename*=UTF-8''test.zip which I haven't managed to remove – barbo Oct 29 '20 at 16:48
  • 1
    You don't need to encode your archive in UTF8. Just remove the charset parameter from you js ``var blobObject = new Blob([response.data], {type: 'application/zip'});`` – Tolbxela Oct 29 '20 at 16:50
  • 1
    In ``filename*=UTF-8''test.zip`` UTF-8 is the encoding of the filename, not of the zip archive! – Tolbxela Oct 29 '20 at 16:53
  • It still downloads the file as being in utf-8, with or without the charset parameter. Ok that sounds right for the filename, good catch! – barbo Oct 29 '20 at 16:59
  • ok I will try that, also I noticed that in my response headers I had this : X-SourceFiles: =?UTF-8?B?QzpcX1Byb2pldHNcTGV4Um9ja19Bbm5vdGF0aW9uXGFwcHNcTGV4Um9jay5XZWIuQXBwXGFwaVxFeHBvcnRcR2V0VXNlcldvcmtDb250ZXh0?= could that also cause a potential problem ? – barbo Oct 29 '20 at 17:17
  • 1
    Never mind my last question, adding responseType fixed it all! Thank you so much! – barbo Oct 29 '20 at 17:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/223869/discussion-between-tolbxela-and-barbo). – Tolbxela Oct 30 '20 at 12:22