FileStreamResult不指示下载开始

时间:2019-07-02 13:31:33

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

我对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的目的吗?

1 个答案:

答案 0 :(得分:0)

好吧,简单的答案似乎是:
由于未设置内容长度,因此在浏览器中看不到下载的开始和进度,因此浏览器无法从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);
    }
}

然后操作代码就很简单

  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可以正常工作,并且看起来更优雅:)