В чем разница между четырьмя результатами файлов в ASP.NET MVC

136

ASP.NET имеет четыре различных типа результатов файла:

  • FileContentResult: отправляет содержимое двоичного файла в ответ.
  • FilePathResult: отправляет содержимое файла в ответ
  • FileResult: возвращает двоичный вывод для записи в ответ
  • FileStreamResult: отправляет двоичное содержимое в ответ с использованием экземпляра Stream

Эти описания взяты из MSDN и, за исключением FileStreamResult, первые три звука идентичны. Так в чем же разница между ними?

Роберт Маклин
источник

Ответы:

176

FileResult является абстрактным базовым классом для всех остальных.

  • FileContentResult - вы используете его, когда у вас есть байтовый массив, который вы хотели бы вернуть в виде файла
  • FilePathResult - когда у вас есть файл на диске и вы хотите вернуть его содержимое (вы указываете путь)
  • FileStreamResult - у вас есть открытый поток, вы хотите вернуть его содержимое в виде файла

Однако вам редко придется использовать эти классы - вы можете просто использовать одну из Controller.Fileперегрузок и позволить ASP.NET MVC позаботиться о вас.

maciejkow
источник
29

Отличный вопрос ... и заслуживает более подробной информации. Я оказываюсь здесь в результате интересной ситуации. Мы доставляли некоторые вложения в формате PDF через среду MVC3 / C #. Наш код был выпущен, и мы начали получать ответы от наших клиентов о том, что загрузка происходила странно, когда они использовали Chrome, и тип файла преобразовывался в «pdf-, attachment.pdf-, attachment». Да ... ты понял ... все это. Таким образом, можно переписать его так, чтобы он был просто «pdf», и файл все равно сохранялся бы неповрежденным, но что за беспорядок!

Итак, чтобы описать исходную ситуацию, мы устанавливали заголовок «Content-Disposition», а затем возвращали FileContentResult ...

var cd = new System.Net.Mime.ContentDisposition
            {
                FileName = result.Attachment.FileName,
                Inline = false
            };
            Response.AppendHeader("Content-Disposition", cd.ToString());

return File(result.Attachment.Data, MimeExtensionHelper.GetMimeType(result.Attachment.FileName), result.Attachment.FileName);

Казалось, хорошо. Работал нормально в IE. Поэтому я провел небольшое исследование и попытался реализовать FileStreamResult (оставив установщик Content-Disposition):

MemoryStream dataStream = new MemoryStream();
dataStream.Write(result.Attachment.Data, 0, result.Attachment.Data.Length);
dataStream.Position = 0;
return new FileStreamResult(dataStream, MimeExtensionHelper.GetMimeType(result.Attachment.FileName));

Это исправило проблему в Chrome! Хммм ... но почему, черт возьми, я должен взять мой совершенно хороший байтовый массив и передать его в поток, а затем вернуть через него, чтобы заставить имя файла работать правильно?

Затем появился скрипач.

С FileContentResult я получил 2 Content-Dispositions в заголовке. С FileStreamResult я получил 1.

FileContentResult добавляет заголовок Content-Disposition при предоставлении имени файла, а Chrome рассматривает кратные значения этого заголовка как ошибку.

Странная реакция ... но определенно это хорошо знать.

beauXjames
источник
3
Просто подсказка, в .NET 4+ вы можете использовать, System.Web.MimeMapping.GetMimeMapping(filename)чтобы собрать тип MIME, если вы не можете легко получить к нему доступ.
GONeale
4
Предоставление имени файла для Fileрезультата означает установку его FileDownloadNameсвойства, которое устанавливает Content-Dispositionзаголовки для вас. И он правильно поддерживает имена файлов utf-8, что не является ContentDispositionвспомогательным классом (см. Мой комментарий здесь для более подробной информации).
Фредерик
1
Да, спасибо @ Frédéric, вы один из всех постов SO объяснили мне, что происходит!
Nacht