144

ASP.NET has four different types of file results:

  • FileContentResult: Sends the contents of a binary file to the response.
  • FilePathResult: Sends the contents of a file to the response
  • FileResult: Returns binary output to write to the response
  • FileStreamResult: Sends binary content to the response by using a Stream instance

Those descriptions are take from MSDN and with the exception of the FileStreamResult the first three sound identical. So what is the difference between them?

Robert MacLean
  • 38,975
  • 25
  • 98
  • 152

2 Answers2

188

FileResult is an abstract base class for all the others.

  • FileContentResult - you use it when you have a byte array you would like to return as a file
  • FilePathResult - when you have a file on disk and would like to return its content (you give a path)
  • FileStreamResult - you have a stream open, you want to return its content as a file

However, you'll rarely have to use these classes - you can just use one of Controller.File overloads and let ASP.NET MVC do the magic for you.

johnnyRose
  • 7,310
  • 17
  • 40
  • 61
maciejkow
  • 6,403
  • 1
  • 27
  • 26
  • One of these rare cases are why I'm here! Using the ApiController for a Xamarin REST api there is no .File so you have to use the above classes. – Ryan D. Feb 28 '22 at 18:43
33

Great question...and deserves more details. I find myself here as a result of an interesting situation. We were delivering some pdf attachments via the MVC3/C# environment. Our code got released and we started getting some responses from our clients that the downloads were behaving strangely when they were using Chrome and the file type was being converted over to 'pdf-, attachment.pdf-, attachment'. Yup...you got it...the whole thing. So, one could rewrite it to just be 'pdf' and the file would still save intact, but what a mess!

So, to describe the initial situation, we were setting the 'Content-Disposition' header then returning a 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);

Seemed good. Worked fine in IE. So I did some research and tried implementing FileStreamResult instead (keeping the Content-Disposition setter):

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));

It fixed the issue in Chrome! Hmmm...but why in the heck should I have to take my perfectly good byte array and stream it and then return it via this to get the file name to work right?

Then came the Fiddler.

With FileContentResult, I got 2 Content-Dispositions in the header. With FileStreamResult, I got 1.

FileContentResult appends a Content-Disposition header when providing the File Name and Chrome considers multiples of this header as an error.

Odd reaction...but definitely one that's good to know.

beauXjames
  • 8,222
  • 3
  • 49
  • 66
  • 3
    Just a tip, in .NET 4+ you can use `System.Web.MimeMapping.GetMimeMapping(filename)` to gather the mime type if you cannot access it easily. – GONeale Oct 30 '14 at 06:16
  • 5
    Providing a file name to a `File` result means setting its [`FileDownloadName`](https://msdn.microsoft.com/en-us/library/system.web.mvc.fileresult.filedownloadname(v=vs.118).aspx) property, which set the `Content-Disposition` headers for you. And it does correctly support utf-8 file names, which does not `ContentDisposition` helper class (see [my comment here](/questions/1012437/uses-of-content-disposition-in-an-http-response-header/22221217#comment57484455_22221217) for more details). – Frédéric Jan 25 '16 at 09:40