Jaka jest różnica między czterema wynikami plików w ASP.NET MVC

136

ASP.NET ma cztery różne typy wyników plików:

  • FileContentResult: wysyła zawartość pliku binarnego do odpowiedzi.
  • FilePathResult: wysyła zawartość pliku do odpowiedzi
  • FileResult: zwraca binarne dane wyjściowe do zapisu w odpowiedzi
  • FileStreamResult: wysyła zawartość binarną do odpowiedzi przy użyciu wystąpienia Stream

Te opisy pochodzą z MSDN iz wyjątkiem FileStreamResult pierwsze trzy brzmią identycznie. Więc jaka jest różnica między nimi?

Robert MacLean
źródło

Odpowiedzi:

176

FileResult jest abstrakcyjną klasą bazową dla wszystkich pozostałych.

  • FileContentResult - używasz go, gdy masz tablicę bajtów, którą chciałbyś zwrócić jako plik
  • FilePathResult - gdy masz plik na dysku i chciałbyś zwrócić jego zawartość (podajesz ścieżkę)
  • FileStreamResult - masz otwarty strumień, chcesz zwrócić jego zawartość jako plik

Jednak rzadko będziesz musiał używać tych klas - możesz po prostu użyć jednego z Controller.Fileprzeciążeń i pozwolić ASP.NET MVC wykonać za Ciebie magię.

maciejkow
źródło
29

Świetne pytanie ... i zasługuje na więcej szczegółów. Znajduję się tutaj w wyniku ciekawej sytuacji. Dostarczaliśmy załączniki PDF za pośrednictwem środowiska MVC3 / C #. Nasz kod został opublikowany i zaczęliśmy otrzymywać odpowiedzi od naszych klientów, że pobrane pliki zachowywały się dziwnie, gdy korzystali z przeglądarki Chrome, a typ pliku był konwertowany na „pdf-, załącznik.pdf-, załącznik”. Tak ... masz to ... cała sprawa. Można więc przepisać go na po prostu „pdf”, a plik nadal byłby zapisywany nienaruszony, ale co za bałagan!

Tak więc, aby opisać sytuację początkową, ustawialiśmy nagłówek „Content-Disposition”, a następnie zwracaliśmy 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);

Wydawało się dobre. Działa dobrze w IE. Zrobiłem więc trochę badań i zamiast tego spróbowałem zaimplementować FileStreamResult (zachowując setter 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));

Naprawiono problem w Chrome! Hmmm ... ale po co u licha miałbym wziąć moją idealnie dobrą tablicę bajtów i przesłać ją strumieniowo, a następnie zwrócić ją przez to, aby nazwa pliku działała poprawnie?

Potem przyszedł Fiddler.

Z FileContentResult otrzymałem w nagłówku 2 Content-Dispositions. Dzięki FileStreamResult mam 1.

FileContentResult dołącza nagłówek Content-Disposition podczas podawania nazwy pliku, a Chrome traktuje wielokrotności tego nagłówka jako błąd.

Dziwna reakcja ... ale zdecydowanie dobrze wiedzieć.

beauXjames
źródło
3
Wskazówka: w .NET 4+ możesz użyć System.Web.MimeMapping.GetMimeMapping(filename)do zebrania typu MIME, jeśli nie masz do niego łatwego dostępu.
GONeale
4
Podanie nazwy pliku Filewynikowi oznacza ustawienie jego FileDownloadNamewłaściwości, która ustawia Content-Dispositiondla Ciebie nagłówki. I poprawnie obsługuje nazwy plików utf-8, co nie ContentDispositionpomaga w klasie (zobacz mój komentarz tutaj po więcej szczegółów).
Frédéric
1
Tak, dziękuję @ Frédéric, tylko ty spośród wszystkich postów SO wyjaśniłeś mi, co się dzieje!
Nacht