On m'a suggéré d'utiliser FileResult pour permettre aux utilisateurs de télécharger des fichiers à partir de mon application Asp.Net MVC. Mais le seul exemple que je puisse trouver concerne toujours les fichiers image (spécifiant le type de contenu image/jpeg).
Mais 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 l’archive de mon site.
J'avais lu une méthode pour le faire (voir un article précédent pour le code), cela fonctionne bien, sauf pour une chose: le nom du fichier qui apparaît dans la boîte de dialogue Enregistrer sous est concaténé à partir du chemin du fichier avec underscores (folder_folder_file.ext). De plus, il semble que les gens pensent que je devrais renvoyer un FileResult au lieu d'utiliser cette classe personnalisée pour laquelle j'ai trouvé BinaryContentResult.
Quelqu'un sait-il comment "faire" un tel téléchargement dans MVC?
EDIT: J'ai eu la réponse (ci-dessous), mais je pensais que je devrais publier le code de travail complet si quelqu'un d'autre est intéressé:
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;
}
Vous pouvez simplement spécifier le type MIME générique du flux d'octets:
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);
}
Le framework MVC supporte cela nativement. Le contrôleur System.Web.MVC.Controller.File fournit des méthodes pour renvoyer un fichier par nom / flux / array =.
Par exemple, en utilisant un chemin virtuel vers le fichier, vous pouvez procéder comme suit.
return File(virtualFilePath, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(virtualFilePath));
Si vous utilisez .NET Framework 4.5, utilisez le MimeMapping.GetMimeMapping (string FileName) pour obtenir le type MIME de votre fichier. Voici comment 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 Nice article où il a créé une classe de résultats Action de téléchargement de fichier Custome. Il vous suffit de spécifier le chemin virtuel du fichier et le nom à enregistrer.
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 physique des fichiers, de sorte que j'ai utilisé cette méthode d'assistance - que j'ai trouvé quelque part dont je ne me souviens plus - pour le convertir en chemin virtuel.
private string GetVirtualPath(string physicalPath)
{
string rootpath = Server.MapPath("~/");
physicalPath = physicalPath.Replace(rootpath, "");
physicalPath = physicalPath.Replace("\\", "/");
return "~/" + physicalPath;
}
Voici la classe complète tirée de l'article de Phill Haack
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);
}
}
Merci à Ian Henry!
Au cas où vous auriez besoin de pour obtenir un fichier à partir de MS SQL Server , voici la solution.
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;
}
Où AppModel est le modèle EntityFramework
et MyFiles présente le tableau dans votre base de données. FileData est varbinary(MAX)
dans MyFiles table.
son simple suffit de donner votre chemin physique dans directoryPath avec le nom de fichier
public FilePathResult GetFileFromDisk(string fileName)
{
return File(directoryPath, "multipart/form-data", fileName);
}
public ActionResult Download()
{
var document = //Obtain document from database context
var cd = new System.Net.Mime.ContentDisposition
{
FileName = document.FileName,
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(document.Data, document.ContentType);
}