我对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的目的吗?
答案 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可以正常工作,并且看起来更优雅:)