C#MVC从S3 Async下载大文件

时间:2017-01-20 11:23:51

标签: c# asp.net-mvc amazon-s3

我必须从aws S3 async下载文件。我有一个锚标签,点击它时,一个方法将在控制器中命中下载。该文件应该在浏览器底部开始下载,就像其他文件下载一样。

在视图中

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

在控制器

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.";   
     }              
}

上述功能使浏览器加载,直到文件完全下载。然后只在底部显示该文件。我无法看到mb是如何下载的 提前谢谢。

2 个答案:

答案 0 :(得分:8)

您必须将ContentLength发送给客户才能显示进度。浏览器没有关于它将接收多少数据的信息。

如果查看由FileStreamResult方法使用的File类的来源,它不会通知客户关于&#34; Content-Length&#34;。 https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/FileStreamResult.cs

替换它,

return File(response, mimeType, downLoadName);

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);

         stream.CopyTo(response.OutputStream);
     }

}

<强>替代

通常,从服务器下载和传送S3文件是一种不好的做法。您的主机帐户将收取两倍的带宽费用。相反,您可以使用签名URL来传递非公共S3对象,只需几秒钟的时间。您只需使用预签名网址

即可
 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.";   
     }              
 }

只要对象没有公共读取策略,没有签名的用户就无法访问对象。

此外,您必须在using周围使用AmazonS3Client以快速处理网络资源,或者只使用一个AmazonS3Client的静态实例来减少不必要的分配和释放。

答案 1 :(得分:2)

据我了解,您希望从服务器到S3进行类似“反向代理”的操作。非常有用的文章如何使用Nginx,你可以在这里找到:https://stackoverflow.com/a/44749584