How do I directly trigger a download window for a downloaded S3 file in .NET?

I still don't know very well about aws s3 storage, but I can already do the basic operations of listing / uploading / downloading objects using nuget awssdks.

However, when downloading an object, I have to create a file on my web server and then make the file available to my user.

It seems to me that I don't know how to perform the direct download to the client.

Is this possible ? If yes, which way to do this?

How to simply transform my current source code for direct download in S3 ?

Thank you very much for guidance.

private void DOWFile(string pFileDir, string pFileName, string pDescription)
{
    //Armazena o path do arquivo
    string lFilePath = pFileDir + pFileName;
    //Verifica se o arquivo existe
    if (File.Exists(lFilePath))
    {
        //Limpa o objeto de resposta
        Response.Clear();
        //Limpa o nome do arquivo
        if (Request.UserAgent.Contains("Firefox")) pDescription = TFileInfo.CONVERTToFileName(pDescription);   
        //Adiciona o cabeçalho do donwload
        Response.AddHeader("Content-Disposition", "attachment; filename=\"" + HttpUtility.UrlPathEncode(pDescription) + "\"");
        //Seta o tipo do arquivo
        Response.ContentType = "application/octet-stream";
        //Passa a referência do arquivo
        Response.WriteFile(lFilePath);
        //Executa o download do arquivo
        Response.Flush();
        //Finaliza o processamento
        HttpContext.Current.Response.SuppressContent = true;
        HttpContext.Current.ApplicationInstance.CompleteRequest();
    }
    else
    {
        //Mostra a mensagem de Erro
        SETErrorInfo(new TErrorInfo(-1, "DOWFile", TErrorInfo.ErrFileNotFound, "FileNotFound - " + lFilePath, false, true, false, true, false, TErrorInfo.TErrType.etLogic));
    }
}

public bool FileDownS3(string pLocalPath, string pFileNameS3)
    {
        IAmazonS3 lClient_Aws = new AmazonS3Client(Amazon.RegionEndpoint.USEast1);
        TransferUtility lUtility = new TransferUtility(lClient_Aws);

        string filename = pLocalPath + pFileNameS3;
        FileStream fs = File.Create(filename);
        fs.Close();


        lUtility.Download(filename, gBucketName, pFileNameS3);

        return true;
    }

Upvotes: 0

Views: 1750

Answers (1)

Ermiya Eskandary
Ermiya Eskandary

Reputation: 23592

You need to return a File object from your handler action, created from a MemoryStream without saving it anywhere locally.

To do so, you first need to get the S3 object in the form of a MemoryStream.

Pass the bucketName & key for your S3 object to AmazonS3Client.GetObjectAsync(...), which returns a response of type GetObjectResponse.

GetObjectResponse has a property called ResponseStream.

This is a stream object which inherits from Amazon.S3.Model.StreamResponse.

You can then copy this to a MemoryStream:

GetObjectResponse response = await s3Client.GetObjectAsync(bucketName, keyName);
MemoryStream memoryStream = new MemoryStream();

using (Stream responseStream = response.ResponseStream)
    responseStream.CopyTo(memoryStream);
}

Once copied, return converted to a File in your controller action.

Make sure to also set a filename (third parameter to File(...) so that the browser can determine the file type for the download:

public async Task<IActionResult> DownloadS3File() {
    ...
    return File(memoryStream.ToArray(), "application/octet-stream", "filename.pdf");
}

This should trigger a download for an object downloaded from Amazon S3.

Upvotes: 1

Related Questions