简体   繁体   English

C#MVC从S3 Async下载大文件

[英]C# MVC Download Big File from S3 Async

I have to download a file from aws S3 async. 我必须从aws S3 async下载一个文件。 I have a anchor tag, on clicking it a method will be hit in a controller for download. 我有一个锚标签,点击它时,一个方法将在控制器中命中下载。 The file should be start downloading at the bottom of the browser, like other file download. 该文件应该在浏览器底部开始下载,就像其他文件下载一样。

In View 在视图中

<a href="/controller/action?parameter">Click here</a>

In Controller 在控制器中

public void action()
{
     try
     {
           AmazonS3Client client = new AmazonS3Client(accessKeyID, secretAccessKey);
           GetObjectRequest req = new GetObjectRequest();
           req.Key = originalName;
           req.BucketName = ConfigurationManager.AppSettings["bucketName"].ToString() + DownloadPath;
           FileInfo fi = new FileInfo(originalName);
           string ext = fi.Extension.ToLower();
           string mimeType = ReturnmimeType(ext);
           var res = client.GetObject(req);
           Stream responseStream = res.ResponseStream;
           Stream response = responseStream;
           return File(response, mimeType, downLoadName);
     }
     catch (Exception)
     {
           failure = "File download failed. Please try after some time.";   
     }              
}

The above function makes the browser to load until the file is fully downloaded. 上述功能使浏览器加载,直到文件完全下载。 Then only the file is visible at the bottom. 然后只在底部显示该文件。 I cant see the how mb is downloading. 我看不到mb是如何下载的。
Thanks in advance. 提前致谢。

You must send ContentLength to client in order to display a progress. 您必须将ContentLength发送到客户端才能显示进度。 Browser has no information about how much data it will receive. 浏览器没有关于它将接收多少数据的信息。

If you look at source of FileStreamResult class, used by File method, it does not inform client about "Content-Length". 如果查看File方法使用的FileStreamResult类的源代码,它不会通知客户端有关“Content-Length”的信息。 https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/FileStreamResult.cs https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/FileStreamResult.cs

Replace this, 替换这个,

return File(response, mimeType, downLoadName);

with

return new FileStreamResultEx(response, res.ContentLength, mimeType, downloadName);


public class FileStreamResultEx : ActionResult{

     public FileStreamResultEx(
        Stream stream, 
        long contentLength,         
        string mimeType,
        string fileName){
        this.stream = stream;
        this.mimeType = mimeType;
        this.fileName = fileName;
        this.contentLength = contentLength;
     }


     public override void ExecuteResult(
         ControllerContext context)
     {
         var response = context.HttpContext.Response; 
         response.BufferOutput = false;
         response.Headers.Add("Content-Type", mimeType);
         response.Headers.Add("Content-Length", contentLength.ToString());
         response.Headers.Add("Content-Disposition","attachment; filename=" + fileName);

         using(stream) { 
             stream.CopyTo(response.OutputStream);
         }
     }

}

Alternative 替代

Generally this is a bad practice to download and deliver S3 file from your server. 通常,从服务器下载和传送S3文件是一种不好的做法。 You will be charged twice bandwidth on your hosting account. 您的主机帐户将收取两倍的带宽费用。 Instead, you can use signed URLs to deliver non public S3 objects, with few seconds of time to live. 相反,您可以使用签名URL来传递非公共S3对象,只需几秒钟的时间。 You could simply use Pre-Signed-URL 您只需使用Pre-Signed-URL即可

 public ActionResult Action(){
     try{
         using(AmazonS3Client client = 
              new AmazonS3Client(accessKeyID, secretAccessKey)){
            var bucketName = 
                 ConfigurationManager.AppSettings["bucketName"]
                .ToString() + DownloadPath;
            GetPreSignedUrlRequest request1 = 
               new GetPreSignedUrlRequest(){
                  BucketName = bucketName,
                  Key = originalName,
                  Expires = DateTime.Now.AddMinutes(5)
               };

            string url = client.GetPreSignedURL(request1);
            return Redirect(url);
         }
     }
     catch (Exception)
     {
         failure = "File download failed. Please try after some time.";   
     }              
 }

As long as object do not have public read policy, objects are not accessible to users without signing. 只要对象没有公共读取策略,没有签名的用户就无法访问对象。

Also, you must use using around AmazonS3Client in order to quickly dispose networks resources, or just use one static instance of AmazonS3Client that will reduce unnecessary allocation and deallocation. 此外,您必须使用using周围AmazonS3Client以便快速处置网络资源,或只使用一个静态实例AmazonS3Client ,将减少不必要的分配和释放。

As i understand, you want to make something like "reverse proxy" from your server to S3. 据我所知,您希望从服务器到S3进行“反向代理”。 Very userful article how to do that with Nginx you can find here: https://stackoverflow.com/a/44749584 非常有用的文章如何使用Nginx,你可以在这里找到: https ://stackoverflow.com/a/44749584

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM