0

I'm mounting a zip file using a MemoryStream.

I know how to download this file using postback.

But I want to pass the contents of the Memory Stream to a Callback and download it in javascript code.

When I try to do this what happens is that the zip file is available for download with the correct size and the list of files inside it is correct including the names, but the files are not valid they look like empty files with 0% compression.

I think my biggest problem is when trying to convert the MemoryStream content to string, there must be some error at this point or in the file download function in javascript.

If anyone can give any tips on how to stream a file to javascript and download it, I appreciate it.

The option to create the zip file on disk is discarded.

Conversion Code used:

> lCallBackResult.HtmlCode = Encoding.ASCII.GetString(lMemoryStream.ToArray());

Download Code used (javascript):

> DOWFileWND(lFileName, 'text/zip', pCallbackResult.htmlcode);

> function DOWFileWND (pFileName, pFileType, pContent)  {
>     
>     let lData = new Blob([pContent], { type: pFileType });
> 
>     //Verifica o navegador
>     if (window.navigator && window.navigator.msSaveOrOpenBlob) 
>     { 
>         //For IE
>         window.navigator.msSaveOrOpenBlob(lData, pFileName);
>     } 
>     else 
>     { 
>         //Cria o link
>         let lLink = document.createElement("a");
>         //Adiciona o link no documento
>         document.body.appendChild(lLink);
>         //Esconde o link
>         lLink.style = "display: none";
> 
>         //Cria a url
>         let lUrl = URL.createObjectURL(lData);
>         //Seta o endereço do link
>         lLink.href =  lUrl;
>         //Seta o nome do arquivo
>         lLink.download = pFileName;
>         //Dispara o link
>         lLink.click();
>         //Deleta o link
>         URL.revokeObjectURL(lLink.href);
>         //Remove o link
>         lLink.remove();
>     }};

Zip Creation Code (C#):

private TCallbackResult CALLExportDOC(TCallbackArgument pCallBackArgument)
    {
        //Cria a isntância dos componentes
        DTSTreeView lDTSTreeView = new DTSTreeView();
        tabTreeViewTableAdapter ltabTreeView = new tabTreeViewTableAdapter();

        //Cria os parâmetros de retorno
        TCallbackResult lCallBackResult = new TCallbackResult();
        //Pega a referência do item
        TTreeItemData lTreeItemData = new TTreeItemData(FValue);

        //Seta as propriedades
        lCallBackResult.Sender = pCallBackArgument.Sender;
        lCallBackResult.Value = pCallBackArgument.Value;
        lCallBackResult.SubValue = pCallBackArgument.SubValue;

        //Armazena o path do arquivo
        string lDocPath = "";

        //Cria o stream de memória
        MemoryStream lMemoryStream = new MemoryStream();
        //Cria o arquivo zip
        ZipOutputStream lZipOutputStream = new ZipOutputStream(lMemoryStream);
        //Cria o buffer
        byte[] lBuffer = new byte[4096];
        //0-9, 9 being the highest compression
        lZipOutputStream.SetLevel(9);

        //Executa a procedure
        ltabTreeView.spn_EXPDocument(lDTSTreeView.tabTreeView, lTreeItemData.IdAmb, lTreeItemData.IdPar, lTreeItemData.IdCur, 0, 1, true, true);

        //Gera o zip do diretório--------------------------------------------------------------------------------------------------------------------

        try
        {
            //Roda em todos os itens retornados
            foreach (DTSTreeView.tabTreeViewRow lCurrentRow in lDTSTreeView.tabTreeView.Rows)
            {
                //Armazena a versão e extensão
                int lVersion_Doc = Convert.ToInt32(lCurrentRow.data_trv.Split('.')[0]);
                string lExtension_Doc = lCurrentRow.data_trv.Split('.')[1];
                //Armazena a versão do arquivo
                string lVersion_Fix = (lVersion_Doc < 10) ? "0" + lVersion_Doc.ToString() : lVersion_Doc.ToString();
                //Cria a entrada no zip
                ZipEntry lZipEntry = new ZipEntry(Path.GetFileName(TFileInfo.CONVERTToFileName(lCurrentRow.descr_trv) + "_AV" + lVersion_Fix + "." + lExtension_Doc));
                //Seta a data da entrada
                lZipEntry.DateTime = DateTime.Now;
                //Vai para a próxima entrada
                lZipOutputStream.PutNextEntry(lZipEntry);
                //Seta o diretório correto do arquivo
                lDocPath = Paths.DOCFisicalPath(lCurrentRow.idcurrent_trv);
                //Abre o arquivo
                using (FileStream lFileStream = File.OpenRead(lDocPath + lCurrentRow.idcurrent_trv.ToString() + "v" + lCurrentRow.data_trv))
                {
                    //Declara a variavel 
                    int lSourceBytes;
                    //Roda no arquivo inteiro
                    do
                    {
                        //Armazena o tamanho do arquivo
                        lSourceBytes = lFileStream.Read(lBuffer, 0, lBuffer.Length);
                        //Grava no arquivo zip
                        lZipOutputStream.Write(lBuffer, 0, lSourceBytes);
                    }
                    while (lSourceBytes > 0);
                }
            }
            //Fecha o arquivo zip
            lZipOutputStream.Finish();
            lZipOutputStream.Close();

            //Armazena o nome do elemento
            string lDescription = GETDescription(lTreeItemData) + ".zip";
            //Limpa o nome do arquivo
            lDescription = TFileInfo.CONVERTToFileName(lDescription);

            //Seta o retorno
            lCallBackResult.Value = lDescription;
            lCallBackResult.HtmlCode =  Encoding.ASCII.GetString(lMemoryStream.ToArray());
        }
        catch
        {
            //Fecha o arquivo zip
            lZipOutputStream.Finish();
            lZipOutputStream.Close();
        }

        //Retorna o valor
        return lCallBackResult;
    }
  • Use Convert.ToBase64String on C# side, then adjust your javascript to convert that base64 string into blob. Using ascii or any other text encoding to represent binary data as string is not a good idea. – Evk Nov 15 '21 at 17:21
  • How i do it ? The C# part ok, but in javascript how convert that base64 string into blob ? – Fabio Alves Francelino Nov 15 '21 at 17:54
  • After you write to memory stream yo uhave to set position to zero before reading. – jdweng Nov 15 '21 at 18:03
  • I appreciate your thoughtfulness in answering, but your answers didn't help me solve the problem, I need you to show me how to do it. – Fabio Alves Francelino Nov 15 '21 at 18:07

1 Answers1

0

C# Code:

lCallBackResult.HtmlCode = Convert.ToBase64String(lMemoryStream.ToArray());

Javascript Code (direct):

const lByteCharacters = atob(pCallbackResult.htmlcode);
const lByteNumbers = new Array(lByteCharacters.length);

for (let i = 0; i < lByteCharacters.length; i++) 
{
    lByteNumbers[i] = lByteCharacters.charCodeAt(i);
}
const lByteArray = new Uint8Array(lByteNumbers);

DOWFileWND(lFileName, 'application/zip', lByteArray);

Javascript Code Caller (slice):

let lBlob = ConvertBase64toBlob(pCallbackResult.htmlcode, 'application/zip', 512);

DOWBlobWND(lFileName, lBlob);

Javascript Code Function (slice):

function ConvertBase64toBlob(b64Data, contentType, sliceSize) 
{
  contentType = contentType || ''; sliceSize = sliceSize || 512;

  let byteCharacters = atob(b64Data);
  let byteArrays = [];

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) 
  {
    let slice = byteCharacters.slice(offset, offset + sliceSize);

    let byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) 
    {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    let byteArray = new Uint8Array(byteNumbers);

    byteArrays.push(byteArray);
  }
    
  let blob = new Blob(byteArrays, {type: contentType});
  return blob;
}