files - fileresult mvc c# ajax
Descargar archivo de cualquier tipo en Asp.Net MVC usando FileResult? (7)
Me han sugerido que debería usar FileResult para permitir que los usuarios descarguen archivos desde mi aplicación Asp.Net MVC. Pero los únicos ejemplos de esto que puedo encontrar siempre tienen que ver con archivos de imagen (especificando el tipo de contenido image / jpeg).
Pero ¿y si no puedo saber el tipo de archivo? Quiero que los usuarios puedan descargar casi cualquier archivo de la zona de archivo de mi sitio.
Había leído un método para hacer esto (ver una publicación anterior para el código), que realmente funciona bien, excepto por una cosa: el nombre del archivo que aparece en el cuadro de diálogo Guardar como se concatena de la ruta del archivo con guiones bajos ( folder_folder_file.ext). Además, parece que la gente piensa que debería devolver un FileResult en lugar de usar esta clase personalizada que encontré en BinaryContentResult.
¿Alguien sabe la forma "correcta" de hacer tal descarga en MVC?
EDITAR: Obtuve la respuesta (a continuación), pero solo pensé que debería publicar el código de trabajo completo si alguien más está interesado:
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;
}
El framework MVC soporta esto de forma nativa. El controlador System.Web.MVC.Controller.File proporciona métodos para devolver un archivo por name / stream / array .
Por ejemplo, utilizando una ruta virtual al archivo, podría hacer lo siguiente.
return File(virtualFilePath, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(virtualFilePath));
GetFile debería estar cerrando el archivo (o abriéndolo dentro de un uso). Luego, puede eliminar el archivo después de la conversión a bytes: la descarga se realizará en ese búfer de bytes.
byte[] GetFile(string 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;
}
Así que en tu método de descarga ...
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));
Gracias a Ian Henry !
En caso de que necesite obtener un archivo de MS SQL Server , esta es la solución.
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;
}
Donde AppModel es el modelo EntityFramework
y MyFiles presenta la tabla en su base de datos. FileData es varbinary(MAX)
en la tabla MyFiles .
Phil Haack tiene un buen article donde creó una clase de Resultado de Acción de Descarga de Archivos de Custome. Solo necesita especificar la ruta virtual del archivo y el nombre que se guardará.
Lo usé una vez y aquí está mi código.
[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 };
}
En mi ejemplo, almacenaba la ruta física de los archivos, así que utilicé este método auxiliar, que encontré en un lugar que no recuerdo, para convertirlo en una ruta virtual.
private string GetVirtualPath(string physicalPath)
{
string rootpath = Server.MapPath("~/");
physicalPath = physicalPath.Replace(rootpath, "");
physicalPath = physicalPath.Replace("//", "/");
return "~/" + physicalPath;
}
Aquí está la clase completa tomada del artículo 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);
}
}
Si está utilizando .NET Framework 4.5, use MimeMapping.GetMimeMapping (string FileName) para obtener el tipo MIME para su archivo. Así es como lo he usado en mi acción.
return File(Path.Combine(@"c:/path", fileFromDB.FileNameOnDisk), MimeMapping.GetMimeMapping(fileFromDB.FileName), fileFromDB.FileName);
Solo puede especificar el tipo MIME genérico de flujo de octetos:
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);
}
es simple, simplemente ingrese su ruta física en directoryPath con nombre de archivo
public FilePathResult GetFileFromDisk(string fileName)
{
return File(directoryPath, "multipart/form-data", fileName);
}