ASP.NET MVC: file response streaming? - asp.net-mvc

When I return a FilePathResult from an MVC action method, which of the following happens (assuming, if it matters, that the file to which the result points is very large):
The file gets loaded in its entirety into the server's memory, and then sent to the client.
The file is somehow streamed to the client, in such a way that it is not at any point fully loaded into the server's memory.
Something else.
If the answer is 1, is it possible to have the file sent as in 2 instead by returning a different type of result?

UPDATE: FilePathResult uses response.TransmitFile which "Writes the specified file directly to an HTTP response output stream, without buffering it in memory.". Here's the source code for MVC.
You can stream data back using the FileStreamResult class:
return new FileStreamResult(stream, "application/pdf")
{
result.FileDownloadName = "somefile.pdf";
};
Or you could redirect to the file like this:
return Redirect("somefile.pdf");

Related

.Net MVC returning a File

I'm working a Controller that will generate/retrieve files. These will optionally set headers.
public IActionResult SampleFileReport()
{
I see the return type is IActionResult (a data contract). I see inside the function I can still set
response.ContentType
Is there a preferred pattern for how to set ContentType in a controller?
I'm thinking it should be part of the DataContract and setting response.contentype is an anti-pattern, however I see examples such as this that utilize it. Returning a file to View/Download in ASP.NET MVC
All you need to do is return File:
public IActionResult SampleFileReport()
{
// do stuff
return File(bytes, mimetype, filename);
}
File also has overloads that accept Stream and string (path and filename to a file on the filesystem) in addition to byte[]. The mimetype is your content type, e.g. application/pdf, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (Excel), etc. The final filename param is optional. If it's provided, a Content-Disposition: attachment header is sent with the response, which prompts the browser to pop a download dialog. Otherwise, the default Content-Disposition: inline is used, and the browser will try to load the returned file directly the browser tab/window, assuming the mime-type is supported for native rendering the browser. If not, then you'll get a download dialog, regardless.
If we are talking about MVC (not .NET Core) then you can change IActionResult to FileContentResult
public FileContentResult SampleFileReport()
{
byte[] fileBytes = GetFileBytes();
return File(fileBytes, MediaTypeNames.Application.Octet, "fileName");
}
Just checked this class still exists. FileContentResult .NET Core

asp.net download controller client from server mvc

When I use #using (Ajax.BeginForm("Generate", "Report")) and press submit button, then the byte file is opened in end of my page
When I use Export
Export2
then the file is downloading and saving in default folder DOWNLOADS. So what is the difference between submit and a href???
public FileContentResult Generate()
{
byte[] resultee2 = new byte[12];
return new FileContentResult(resultee2, "text/plain") { FileDownloadName = "myfile.txt" };
}
And how can I create downloading file to folder after submitting form?
I have a form with fields, then I press submit button and values from fields are being send to server, server is generating byte array and then server is responding that byte array then controller has this byte array and then I want to convert this byte array to text and send to client as Download File.
Form file downloads over AJAX do not always function like opening a file from a hyperlink click or after a standard form post action. What I've done in the past is define an action:
public ActionResult Download(long id)
{
//get record info
return File(fileStream, "application/pdf");
}
I was working with PDFS in this example (note the browser by default, would open in a new tab and not prompt to download directly). And access this action via javascript:
window.open("Download?id=" + id, "_blank");
This will call the download option and return the contents. Note that this requires using some persistence mechanism, like storing the file on disk or in the database, or recreating the file from data in the database.
You also have more control if you use jQuery's $.ajax method because you have more control over the request and response, and could possibly return file data back through the AJAX call response...

How to show error view after CSV export after directly writing to HttpContext.Current.Response?

In an ASP.NET MVC web application I write directly to HttpContext.Current.Response to export to a CSV file.
This is done in an action in my controller. So I do something like this:
try
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Cookies.Clear();
HttpContext.Current.Response.Charset = System.Text.UTF8Encoding.UTF8.WebName;
HttpContext.Current.Response.ContentEncoding = System.Text.UTF8Encoding.UTF8;
HttpContext.Current.Response.AppendHeader("Pragma", "no-cache");
HttpContext.Current.Response.AppendHeader("Content-Disposition", fileName);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.Write("a,b,c\n");
}
catch(Exception)
{
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.SuppressContent = true;
return RedirectToAction("Error");
//return PartialView("ErrorExportingData"); //Prefered!
}
This works without any problem, except that the page is not redirected (or the partial view is not displayed). I guess the problem is that a complete response was already created (and completed).
I flush the response and suppress the content before the redirect, so the exception stack trace does not end up in my CSV file. After this I somehow need to build a new response.
My question is: In this situation, How can I redirect to an error page, after an exception was thrown?
(If somebody wonders why I want to write directly to HttpContext.Current.Response? This is because it is the fastest way to write many records to a CSV file, using a SqlDataReader.)

Multi Post for Action with return File in ASP.NET MVC

Assume this code in One of my Actions
[HttpPost]
public ActionResult Generate (Params){
....
InsertOneRawToDB();
return RedirectToAction("Index", new { info = info });
}
So every thing is OK yet but when I change return to:
InsertOneRawToDB();
byte[] myfile = GenerateAZipFile();
return File( myfile , "application/zip" , "MyFileName");
In this case I see a weird behavior: before return, One raw inserted to DB, and after return another raw inserted, it seems the InsertOneRawToDB called again.
Does any one know about this? what happening here?
PS: I use Visual Studio 2012 RTM + ASP.NET MVC4
PS: OK I Use IDM (Internet Download Manager) to download zip file and that cause MultiPost on this Action So How can I handle this?
Based on your conclusion that the problem is related to using a download manager... That's what download mangers do. They create multiple connections to the file.
One thing you could do is store a session variable that says "Already started downloading", and then only insert the record the first time.
however if the user legitimately downloaded the file multiple times then you would only get one record.
Another option would be to examine the Http headers and look for the "Range" header, which is what is used to download a file in multiple pieces (or resume a file). You would then have to take the Range parameters and only return the portion of the file requested.
Here's an example of how to do a Ranged download: http://tpeczek.com/2011/10/range-requests-in-aspnet-mvc.html
I'm actually quite surprised that this hasn't come up before... I guess most people don't do database actions in a download action or notice it.
You can redirect to new action and in this new action return file.
[HttpPost]
public ActionResult Generate (Params){
....
InsertOneRawToDB();
return RedirectToAction("GetFile"};
}
[HttpGet]
public ActionResult GetFile
{
byte[] myfile = GenerateAZipFile();
return File(myfile, "application/zip", "filename.ext");
}

ASP.NET MVC 3 provide large file download to browser while server retrieves file from elsewhere

I need to provide a file-download feature where the web server retrieves the file from another source (via HTTP) and simultaneously streams it to the browser. I am guessing that using MVC's Controller.File ActionResult will not work, but I wrote a prototype like this anyway:
public ActionResult Download()
{
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create("http://somewhere/somefile.pdf");
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
Stream stream = webResponse.GetResponseStream();
var mimeType = "application/pdf";
var fileName = "somefile.pdf";
return File(stream, mimeType, fileName);
}
This works fine, but there is no way to call Close() on the HttpWebResponse and Stream after the return statement. The help on the HttpWebResponse.GetResponseStream method says, "You must call either the Stream.Close or the HttpWebResponse.Close method to close the stream and release the connection for reuse. It is not necessary to call both Stream.Close and HttpWebResponse.Close, but doing so does not cause an error. Failure to close the stream will cause your application to run out of connections."
Should I create an HttpHandler and manually read bytes from the source stream and write them out to the response, along the lines of this or this? Is there another approach I'm not aware of?
While I'm not directly familiar with trying something like this, my first though was to do what you suggested in regards to reading in the stream, closing the connection, then returning the bytes as the response. Being a stream, I don't know how you can get around leaving it open for the sake of returning its contents as you do in your prototype, but then being able to close it when you're done.

Resources