Problem
It’s been suggested that I utilize FileResult to let users download files from my Asp.Net MVC application. However, the only instances I can locate invariably involve picture files (with the content type image/jpeg specified).
But what if I don’t know what type of file I’m dealing with? I want people to be able to download almost any file from my site’s filearea.
I saw a method for achieving this (see a previous post for the code) that works perfectly, except for one thing: the name of the file that appears in the Save As window is made up of underscores concatenated from the file path (folder folder file.ext). Also, it appears that instead of utilizing this custom class BinaryContentResult, folks believe I should return a FileResult.
Anyone know how to do a download in MVC the “right” way?
EDIT: I received the answer (below), but I figured I’d share the complete functional code in case anyone else is interested:
public ActionResult Download(string filePath, string fileName)
{
string fullName = Path.Combine(GetBaseDir(), filePath, fileName);
byte[] fileBytes = GetFile(fullName);
return File(
fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
byte[] GetFile(string s)
{
System.IO.FileStream fs = System.IO.File.OpenRead(s);
byte[] data = new byte[fs.Length];
int br = fs.Read(data, 0, data.Length);
if (br != fs.Length)
throw new System.IO.IOException(s);
return data;
}
Asked by Anders
Solution #1
You can just give the MIME type octet-stream:
public FileResult Download()
{
byte[] fileBytes = System.IO.File.ReadAllBytes(@"c:\folder\myfile.ext");
string fileName = "myfile.ext";
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
Answered by Ian Henry
Solution #2
This is built-in to the MVC framework. The System.Web.MVC.Controller is a controller in System.Web.MVC. The File controller has methods for getting a file by name, stream, or array.
You could, for example, do the following with a virtual path to the file.
return File(virtualFilePath, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(virtualFilePath));
Answered by Jonathan
Solution #3
You can use MimeMapping if you’re using the.NET Framework 4.5. To get the MIME-Type for your file, use GetMimeMapping(string FileName). This is how I put it to work in my activity.
return File(Path.Combine(@"c:\path", fileFromDB.FileNameOnDisk), MimeMapping.GetMimeMapping(fileFromDB.FileName), fileFromDB.FileName);
Answered by Salman Hasrat Khan
Solution #4
Phil Haack published an article in which he describes how to develop a Custom File Download Action Result class. Only the virtual path of the file and the name to save it as are required.
I’ve used it before, and here’s the code I used.
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Download(int fileID)
{
Data.LinqToSql.File file = _fileService.GetByID(fileID);
return new DownloadResult { VirtualPath = GetVirtualPath(file.Path),
FileDownloadName = file.Name };
}
I was saving the physical path of the files in my example, thus I used this helper technique -that I can’t remember where I discovered it- to convert it to a virtual path.
private string GetVirtualPath(string physicalPath)
{
string rootpath = Server.MapPath("~/");
physicalPath = physicalPath.Replace(rootpath, "");
physicalPath = physicalPath.Replace("\\", "/");
return "~/" + physicalPath;
}
The following is the complete class, as extracted from Phill Haack’s paper.
public class DownloadResult : ActionResult {
public DownloadResult() {}
public DownloadResult(string virtualPath) {
this.VirtualPath = virtualPath;
}
public string VirtualPath {
get;
set;
}
public string FileDownloadName {
get;
set;
}
public override void ExecuteResult(ControllerContext context) {
if (!String.IsNullOrEmpty(FileDownloadName)) {
context.HttpContext.Response.AddHeader("content-disposition",
"attachment; filename=" + this.FileDownloadName)
}
string filePath = context.HttpContext.Server.MapPath(this.VirtualPath);
context.HttpContext.Response.TransmitFile(filePath);
}
}
Answered by Manaf Abu.Rous
Solution #5
Ian Henry is to be commended!
This is the option if you need to get a file from MS SQL Server.
public FileResult DownloadDocument(string id)
{
if (!string.IsNullOrEmpty(id))
{
try
{
var fileId = Guid.Parse(id);
var myFile = AppModel.MyFiles.SingleOrDefault(x => x.Id == fileId);
if (myFile != null)
{
byte[] fileBytes = myFile.FileData;
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, myFile.FileName);
}
}
catch
{
}
}
return null;
}
Where AppModel denotes an EntityFramework model and MyFiles denotes a database table. In the MyFiles table, FileData is varbinary(MAX).
Answered by NoWar
Post is based on https://stackoverflow.com/questions/3604562/download-file-of-any-type-in-asp-net-mvc-using-fileresult