【问题标题】:FileStreamResult does not indicate download startFileStreamResult 不表示下载开始
【发布时间】:2019-11-13 04:08:35
【问题描述】:

我的 MVC 控制器上有以下操作:

  public async Task<FileStreamResult> Contact()
        {
            IAmazonS3 s3Client = GetS3Client();
            GetObjectRequest request = new GetObjectRequest
            {
                BucketName = bucketName,
                Key = objectKey,
            };
            GetObjectResponse response = await s3Client.GetObjectAsync(request).ConfigureAwait(false);
            return File(response.ResponseStream, "application/octet-stream", "SomeFile.exe");
        }

我正在测试的文件约为 10-30MB。

当这个动作被页面上的按钮触发时,不会指示下载开始。 浏览器静默等待文件完全可用(这需要相当长的时间),然后它突然将它们显示为已下载。

为什么不显示下载已开始且正在进行中?如何启用它?

文件非常大,我希望将它们发送/流式传输到客户端而不加载到内存或预先保存在我的服务器上,所以我想这就是 FileStreamResult 的用途吗?

【问题讨论】:

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


    【解决方案1】:

    嗯,简单的答案似乎是:
    在浏览器中看不到下载开始和进度,因为没有设置内容长度,所以浏览器无法从FileStreamResult.

    所以,设置它应该足够了。对我来说,通过使用允许设置长度的东西扩展 ActionResult 效果最好:

    public class FileStreamWithLengthResult : ActionResult
    {
        private Stream stream;
        private string mimeType;
        private string fileName;
        private long contentLength;
    
        public FileStreamWithLengthResult(Stream stream,string mimeType,string fileName)
        {
            this.stream = stream;
            this.mimeType = mimeType;
            this.fileName = fileName;
            this.contentLength = stream.Length;
        }
    
    
        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);
        }
    }
    

    那么Action代码就这么简单

      public async Task<FileStreamWithLengthResult> Download()
            {
                IAmazonS3 s3Client = GetS3Client();
                GetObjectRequest request = new GetObjectRequest
                {
                    BucketName = bucketName,
                    Key = objectKey,
                };
                GetObjectResponse response = await s3Client.GetObjectAsync(request).ConfigureAwait(false);
                return new FileStreamWithLengthResult(response.ResponseStream, "application/octet-stream", "SomeFile.exe");
    
            }
    

    根据this 的回答。

    另外,对我有用的是像这样设置“Content-Lenght”标题:

    this.ControllerContext.HttpContext.Response.AddHeader("Content-Length", response.ResponseStream.Length.ToString()); //not worked
    this.Response.AddHeader("Content-Length", response.ResponseStream.Length.ToString()); //not worked
    this.HttpContext.Response.AddHeader("Content-Length", response.ResponseStream.Length.ToString()); //not worked
    

    我想这些都指向同一个对象实例,但不知道为什么它不起作用。无论如何,自定义 FileStreamWithLengthResult 工作正常,看起来更优雅:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-20
      • 1970-01-01
      • 2014-11-21
      • 2017-08-10
      • 2017-03-23
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      相关资源
      最近更新 更多