Télécharger un fichier de n’importe quel type dans Asp.Net MVC en utilisant FileResult?

Il m’a été suggéré que je devrais utiliser FileResult pour permettre aux utilisateurs de télécharger des fichiers à partir de mon application Asp.Net MVC. Mais les seuls exemples que je puisse trouver concernent toujours les fichiers image (spécifiant le type de contenu image / jpeg).

Mais que faire si je ne peux pas connaître le type de fichier? Je souhaite que les utilisateurs puissent télécharger à peu près tous les fichiers de la zone de leur site.

J’avais lu une méthode pour le faire (voir un article précédent pour le code), qui fonctionne bien, sauf une chose: le nom du fichier qui apparaît dans la boîte de dialog Enregistrer sous est concaténé à partir du chemin de fichier avec des traits de soulignement ( folder_folder_file.ext). En outre, il semble que les gens pensent que je devrais retourner un FileResult au lieu d’utiliser cette classe personnalisée pour laquelle j’avais trouvé BinaryContentResult.

Quelqu’un sait-il la façon “correcte” de faire un tel téléchargement dans MVC?

EDIT: J’ai la réponse (ci-dessous), mais je pensais juste que je devrais publier le code de travail complet si quelqu’un d’autre était intéressé:

public ActionResult Download(ssortingng filePath, ssortingng fileName) { ssortingng fullName = Path.Combine(GetBaseDir(), filePath, fileName); byte[] fileBytes = GetFile(fullName); return File( fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName); } byte[] GetFile(ssortingng 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; } 

Vous pouvez simplement spécifier le type MIME d’octet-stream générique:

 public FileResult Download() { byte[] fileBytes = System.IO.File.ReadAllBytes(@"c:\folder\myfile.ext"); ssortingng fileName = "myfile.ext"; return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName); } 

Le framework MVC le supporte nativement. Le contrôleur System.Web.MVC.Controller.File fournit des méthodes pour renvoyer un fichier par nom / stream / tableau .

Par exemple, en utilisant un chemin virtuel vers le fichier, vous pouvez effectuer les opérations suivantes.

 return File(virtualFilePath, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(virtualFilePath)); 

Si vous utilisez .NET Framework 4.5, vous devez utiliser MimeMapping.GetMimeMapping (ssortingng FileName) pour obtenir le type MIME pour votre fichier. C’est comme ça que je l’ai utilisé dans mon action.

 return File(Path.Combine(@"c:\path", fileFromDB.FileNameOnDisk), MimeMapping.GetMimeMapping(fileFromDB.FileName), fileFromDB.FileName); 

Phil Haack a un bel article dans lequel il a créé une classe Custome File Download Action Result. Il vous suffit de spécifier le chemin d’access virtuel du fichier et le nom à enregistrer en tant que.

Je l’ai utilisé une fois et voici mon code.

  [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 }; } 

Dans mon exemple, je stockais le chemin d’access physique des fichiers, j’ai donc utilisé cette méthode d’assistance – que j’ai trouvée quelque part dont je ne me souviens pas – pour la convertir en chemin virtuel

  private ssortingng GetVirtualPath(ssortingng physicalPath) { ssortingng rootpath = Server.MapPath("~/"); physicalPath = physicalPath.Replace(rootpath, ""); physicalPath = physicalPath.Replace("\\", "/"); return "~/" + physicalPath; } 

Voici le cours complet tiré de l’article de Phill Haack

 public class DownloadResult : ActionResult { public DownloadResult() {} public DownloadResult(ssortingng virtualPath) { this.VirtualPath = virtualPath; } public ssortingng VirtualPath { get; set; } public ssortingng FileDownloadName { get; set; } public override void ExecuteResult(ControllerContext context) { if (!Ssortingng.IsNullOrEmpty(FileDownloadName)) { context.HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + this.FileDownloadName) } ssortingng filePath = context.HttpContext.Server.MapPath(this.VirtualPath); context.HttpContext.Response.TransmitFile(filePath); } } 

Merci à Ian Henry !

Dans le cas où vous devez obtenir un fichier à partir de MS SQL Server, voici la solution.

 public FileResult DownloadDocument(ssortingng id) { if (!ssortingng.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; } 

EntityFramework est le modèle EntityFramework et MyFiles présente la table dans votre firebase database. FileData est varbinary(MAX) dans la table MyFiles .

sa simple donne juste votre chemin physique dans directoryPath avec le nom de fichier

 public FilePathResult GetFileFromDisk(ssortingng fileName) { return File(directoryPath, "multipart/form-data", fileName); } 

GetFile devrait fermer le fichier (ou l’ouvrir dans un using). Ensuite, vous pouvez supprimer le fichier après la conversion en octets – le téléchargement se fera sur ce tampon d’octets.

  byte[] GetFile(ssortingng s) { byte[] data; using (System.IO.FileStream fs = System.IO.File.OpenRead(s)) { 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; } 

Donc dans votre méthode de téléchargement …

  byte[] fileBytes = GetFile(file); // delete the file after conversion to bytes System.IO.File.Delete(file); // have the file download dialog only display the base name of the file return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(file));