2010-07-08 10 views
51

¿Hay alguna forma de transmitir un archivo utilizando ASP.NET MVC FileContentResult dentro del navegador con un nombre específico?¿Transmitir archivo utilizando ASP.NET MVC FileContentResult en un navegador con un nombre?

He notado que puede tener un FileDialog (Abrir/Guardar) o puede transmitir el archivo en una ventana del navegador, pero luego usará el ActionName cuando intente guardar el archivo.

que tienen el siguiente escenario:

byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote); 
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId)); 

Cuando utilizo esto, puedo transmitir los bytes, pero se da un diálogo de abrir/guardar archivos para el usuario. Me gustaría transmitir este archivo en una ventana del navegador.

Si solo uso FilePathResult, muestra el archivo en una ventana del navegador, pero cuando hago clic en el botón "Guardar" para guardar el archivo en PDF, me muestra el nombre de la acción como el nombre del archivo.

Alguien ha encontrado esto?

Respuesta

11

Esto podría ser útil para cualquier otro que se enfrenta a este problema. Finalmente descubrí una solución. Resulta que, incluso si usamos el en línea para "disposición de contenido" y especificamos un nombre de archivo, los navegadores aún no usan el nombre del archivo. En cambio, los navegadores intentan interpretar el nombre del archivo en función de la ruta/URL.

Puede leer más sobre este URL: Securly download file inside browser with correct filename

Esto me dio una idea, acabo de crear mi ruta URL que convertiría la URL y terminar con el nombre del archivo que quería dar al archivo . Entonces, por ejemplo, mi llamada al controlador original solo consistía en pasar el Id de pedido del pedido que se estaba imprimiendo. Esperaba que el nombre del archivo fuera del formato Order {0} .pdf donde {0} es el ID del pedido. Del mismo modo para las comillas, quería Cita {0} .pdf.

En mi controlador, simplemente seguí adelante y agregué un parámetro adicional para aceptar el nombre del archivo. Pasé el nombre del archivo como parámetro en el método URL.Action.

Entonces creó una nueva ruta que asignar esa URL con el formato: http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf

 

routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}", 
       new { controller = "ShoppingCart", action = "PrintQuote" } 
       , new string[] { "x.x.x.Controllers" } 
      ); 
 

Esto más o menos resuelto mi problema. ¡Espero que esto ayude a alguien!

Cheerz, Anup

+0

¡Un truco, pero un truco muy efectivo! ¡Gracias! –

+0

Lamentablemente, aún se necesita con IE 11. No es necesario con Chrome y Firefox. –

79
public ActionResult Index() 
{ 
    byte[] contents = FetchPdfBytes(); 
    return File(contents, "application/pdf", "test.pdf"); 
} 

y para abrir el PDF en el navegador tendrá que establecer la cabecera Content-Disposition:

public ActionResult Index() 
{ 
    byte[] contents = FetchPdfBytes(); 
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf"); 
    return File(contents, "application/pdf"); 
} 
+0

Hola Darin, Esto abre un Diálogo ABRIR/GUARDAR como mencioné. Quiero que abra un archivo dentro del navegador. –

+1

@Anup, por favor vea mi actualización. –

+0

¿podemos tener un valor genérico en lugar de "aplicación/pdf"? como que no estoy seguro del tipo de archivo. es el usuario que lo subió en primer lugar – neebz

38

En realidad, la forma absolutamente más fácil es hacer lo siguiente ...

byte[] content = your_byte[]; 

FileContentResult result = new FileContentResult(content, "application/octet-stream") 
       { 
        FileDownloadName = "your_file_name" 
       }; 

return result; 
+1

Nah! .. mi respuesta es más fácil, http://stackoverflow.com/a/29392930/193634 –

+2

Estoy de acuerdo si la pregunta original no incluye una matriz de bytes. – azarc3

0
public FileContentResult GetImage(int productId) { 
    Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId); 
    if (prod != null) { 
     return File(prod.ImageData, prod.ImageMimeType); 
     } else { 
     return null; 
    } 
} 
5

respuestas anteriores son correctas: la adición de la línea ...

Response.AddHeader("Content-Disposition", "inline; filename=[filename]"); 

... provocará que múltiples encabezados Content-Disposition se envíen al navegador.Esto sucede b/c FileContentResult aplica internamente el encabezado si le proporciona un nombre de archivo. Una solución alternativa, y bastante simple, es simplemente crear una subclase de FileContentResult y anular su método ExecuteResult(). Aquí hay un ejemplo que crea la instancia de una instancia de la clase System.Net.Mime.ContentDisposition (el mismo objeto que se utiliza en el FileContentResult aplicación interna) y lo pasa a la nueva clase:

public class FileContentResultWithContentDisposition : FileContentResult 
{ 
    private const string ContentDispositionHeaderName = "Content-Disposition"; 

    public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition) 
     : base(fileContents, contentType) 
    { 
     // check for null or invalid ctor arguments 
     ContentDisposition = contentDisposition; 
    } 

    public ContentDisposition ContentDisposition { get; private set; } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     // check for null or invalid method argument 
     ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName; 
     var response = context.HttpContext.Response; 
     response.ContentType = ContentType; 
     response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString()); 
     WriteFile(response); 
    } 
} 

En su Controller, o en una base de Controller, puede escribir un ayudante sencilla de ejecutar un FileContentResultWithContentDisposition y luego llamarlo desde su método de acción, así:

protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition) 
{ 
    var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition); 
    return result; 
} 

public ActionResult Report() 
{ 
    // get a reference to your document or file 
    // in this example the report exposes properties for 
    // the byte[] data and content-type of the document 
    var report = ... 
    return File(report.Data, report.ContentType, new ContentDisposition { 
     Inline = true, 
     FileName = report.FileName 
    }); 
} 

Ahora el archivo se enviará al navegador con el nombre de archivo que usted elija y con un encabezado de contenido-disposición de " inline; filename = [nombre de archivo] ".

Espero que ayude!

+0

Primero fui la clase de ayuda 'ContentDisposition', solo para darme cuenta de que MVC también lo estaba usando internamente, pero con algún truco para manejar correctamente el nombre de archivo utf-8. La clase de ayuda 'ContentDisposition' lo hace incorrectamente cuando tiene que codificar valores utf-8. Para obtener más información, consulte [mi comentario aquí] (/ questions/1012437/uses-of-content-disposition-in-an-http-response-header/22221217 # comment57484455_22221217). –

4

La manera más fácil absoluta para transmitir un archivo en el navegador usando ASP.NET MVC es la siguiente:

public ActionResult DownloadFile() { 
    return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf"); 
} 

Esto es más fácil que el método sugerido por @ azarc3 ya que ni siquiera es necesario para leer los bytes .

crédito va a: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response

** Editar **

Al parecer, mi 'respuesta' es la misma que la pregunta de la OP. Pero no estoy enfrentando el problema que está teniendo. Probablemente este era un problema con la versión anterior de ASP.NET MVC?

+0

Su problema se puede abstraer a 'MVC enviar un encabezado 'content-disposition' con la disposición' attachment' al especificar un nombre de archivo, ¿cómo hacer que lo envíe como 'inline'? Pruebe los encabezados de respuesta de su solución, normalmente verá 'attachment' también. –

Cuestiones relacionadas