FileStreamResult не указывает на начало загрузки - PullRequest
2 голосов
/ 02 июля 2019

У меня есть следующее действие на контроллере 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-30 МБ.

Когда это действие вызывается кнопкойна странице начало загрузки не указано. Браузер молча ожидает полного доступа к файлу (что занимает довольно много времени), а затем внезапно показывает их как загруженные.

Почему это не показывает, что загрузка начата и находится в процессе?Как включить это?

Файлы довольно велики, и я хочу, чтобы они отправлялись / передавались в потоковом режиме клиенту без загрузки в память или предварительного сохранения на моем сервере, поэтому я полагаю, для этого предназначен FileStreamResult?

1 Ответ

0 голосов
/ 02 июля 2019

Что ж, простой ответ выглядит следующим образом:
Начало и ход загрузки не видны в браузере, поскольку длина контента не установлена ​​, поэтому браузер не может определить их из 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");

        }

Согласно этот ответ.

Кроме того, что не работало для меня, так это установка заголовка «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 работает нормально и выглядит более элегантно:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...