Stream file using ASP.NET MVC FileContentResult in a browser with a name?

Is there a way to stream a file using ASP.NET MVC FileContentResult within the browser with a specific name?

I have noticed that you can either have a FileDialog (Open/Save) or you can stream the file in a browser window, but then it will use the ActionName when you try to save the file.

I have the following scenario:

byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));

When I use this, I can stream the bytes, but a OPEN/SAVE file dialog is given to the user. I would like to actually stream this file in a browser window.

If I just use the FilePathResult, it shows the file in a browser window, but then when I click on "Save" button to save the file in PDF, it shows me the Action Name as the name of the file.

Has anyone encountered this?

public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    return File(contents, "application/pdf", "test.pdf");
}

and for opening the PDF inside the browser you will need to set the Content-Disposition header:

public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
    return File(contents, "application/pdf");
}

Is there a way to stream a file using ASP.NET MVC FileContentResult within the browser with a specific name? I have noticed that you can either have a FileDialog (Open/Save) or you can stream the file in a browser window, but then it will use the ActionName when you try to save the file.

Actually, the absolutely easiest way is to do the following...

byte[] content = your_byte[];

FileContentResult result = new FileContentResult(content, "application/octet-stream") 
{
  FileDownloadName = "your_file_name"
};

return result;

In a regular MVC controller, we can output pdf with a FileContentResult.. public FileContentResult Test(TestViewModel vm) { var stream = new MemoryStream(); // add content to the stream.

This might be helpful for whoever else faces this problem. I finally figured out a solution. Turns out, even if we use the inline for "content-disposition" and specify a file name, the browsers still do not use the file name. Instead browsers try and interpret the file name based on the Path/URL.

You can read further on this URL: Securly download file inside browser with correct filename

This gave me an idea, I just created my URL route that would convert the URL and end it with the name of the file I wanted to give the file. So for e.g. my original controller call just consisted of passing the Order Id of the Order being printed. I was expecting the file name to be of the format Order{0}.pdf where {0} is the Order Id. Similarly for quotes, I wanted Quote{0}.pdf.

In my controller, I just went ahead and added an additional parameter to accept the file name. I passed the filename as a parameter in the URL.Action method.

I then created a new route that would map that URL to the format: http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf


routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}",
                new { controller = "ShoppingCart", action = "PrintQuote" }
                , new string[] { "x.x.x.Controllers" }
            );

This pretty much solved my issue. Hoping this helps someone!

Cheerz, Anup

If you're simply trying to download the binary data, you should be using the FileContentResult type or the FileStreamResult type, accessible as the File method on the Controller class. Here's a simple example:

Previous answers are correct: adding the line...

Response.AddHeader("Content-Disposition", "inline; filename=[filename]");

...will causing multiple Content-Disposition headers to be sent down to the browser. This happens b/c FileContentResult internally applies the header if you supply it with a file name. An alternative, and pretty simple, solution is to simply create a subclass of FileContentResult and override its ExecuteResult() method. Here's an example that instantiates an instance of the System.Net.Mime.ContentDisposition class (the same object used in the internal FileContentResult implementation) and passes it into the new class:

public class FileContentResultWithContentDisposition : FileContentResult
{
    private const string ContentDispositionHeaderName = "Content-Disposition";

    public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
        : base(fileContents, contentType)
    {
        // check for null or invalid ctor arguments
        ContentDisposition = contentDisposition;
    }

    public ContentDisposition ContentDisposition { get; private set; }

    public override void ExecuteResult(ControllerContext context)
    {
        // check for null or invalid method argument
        ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName;
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString());
        WriteFile(response);
    }
}

In your Controller, or in a base Controller, you can write a simple helper to instantiate a FileContentResultWithContentDisposition and then call it from your action method, like so:

protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
{
    var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition);
    return result;
}

public ActionResult Report()
{
    // get a reference to your document or file
    // in this example the report exposes properties for
    // the byte[] data and content-type of the document
    var report = ...
    return File(report.Data, report.ContentType, new ContentDisposition {
        Inline = true,
        FileName = report.FileName
    });
}

Now the file will be sent to the browser with the file name you choose and with a content-disposition header of "inline; filename=[filename]".

I hope that helps!

I was trying to download a self generated excel file. Using the stream.GetBuffer() always returned an corrupted excel. If instead I use stream.ToArray() the file is generated without a problem. Hope this helps someone. – afnpires Apr 5 '16 at 15:07

The absolute easiest way to stream a file into browser using ASP.NET MVC is this:

public ActionResult DownloadFile() {
    return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}

This is easier than the method suggested by @azarc3 since you don't even need to read the bytes.

Credit goes to: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response

** Edit **

Apparently my 'answer' is the same as the OP's question. But I am not facing the problem he is having. Probably this was an issue with older version of ASP.NET MVC?

Is there a way to stream a file using ASP.NET MVC FileContentResult within the browser with a specific name? I have noticed that you can either have a FileDialog (Open/Save) or you can stream the file in a browser window, but then it will use the ActionName when you try to save the file.

FileResult is the parent of all file-related action results. There is a method on ControllerBase class called File. This method accepts a set of parameters based on the type of file and its location, which maps directly to the more specific return types. I’ll discuss how to use all the FileResult actions available in ASP.Net Core MVC. Here is

How a browser knows what file type is returned from the server? The Content-Type header is the one that says the browser what kind of file is being returned from the server. For example, to return a pdf file from the server the Content-Type should be set to application/pdf.

preface Some time ago, the project was on line. I was really busy. Recently, I began to study it ASP.NET Core I’m going to write a series, but I haven’t thought of the catalogue yet ASP.NET Core 2.0 is mature now. Try to use it in the next project text 1. Use model binding to …

Comments
  • Hello Darin, This opens up an OPEN/SAVE Dialog like I mentioned. I want this to open a file inside the browser.
  • can we have a generic value instead of "application/pdf" ? like I am not sure the type of the file. it's the user who uploaded it i the first place
  • We used this approach, and it causes MVC3 to send 2 Content-Disposition headers to the browser, which causes Chrome and Firefox to not display the file. stackoverflow.com/q/8616691/304832
  • @AnilSoman, it makes no sense to call a controller action that returns a file with AJAX. You will never get any file open box if you use AJAX.
  • @AnilSoman, sorry that's impossible with AJAX. You could use a normal image button that submits the form without any AJAX call.
  • I would agree if the original question didn't include a byte array.
  • This does not work if you have a file stream like I do unless you want to read the stream into an array.
  • @SteveHiner The original post specifically called out byte[] as the data to be rendered.
  • A hack, but a very effective hack! Thanks!
  • Unfortunately, still needed with IE 11. Not needed with Chrome and Firefox.
  • Brillant worked for me... but one gotcha I discovered, ensure that any static file handlers don't intercept the request before it gets to managed code, that was my additional hurdle. i.e by default requests for anything *.jpg for instance don't go anywhere near the managed code, so routes are not even checked, additional here
  • I have gone the ContentDisposition helper class way first, just to realize MVC was using it internally too, but with some hack for correctly handling utf-8 file name. ContentDisposition helper class does it wrong when it has to encode utf-8 values. For more details, see my comment here.
  • Its issue can be abstracted to 'MVC send a content-disposition header with attachment disposition when specifying a file name, how to get it send it as inline? Test your solution response headers, you would normally see attachment too.
  • For me this does the trick. Didn't think it was that simple until Rosdi pointed it out