2011-12-23 7 views
10

Tenemos algunos archivos almacenados en la base de datos sql. En un formulario ASP.NET MVC3, mostramos 2 enlaces:Cómo evitar los encabezados duplicados de disposición de contenido con MVC3 FileContentResult?

Ver este archivo | Descargar este archivo

Estos enlaces van a estos métodos de acción correspondientes. La descarga funciona como se esperaba: al hacer clic en un enlace se fuerza un diálogo de guardar en el navegador. Sin embargo, la pantalla está causando que se envíen encabezados duplicados de Content-Disposition al navegador, lo que da como resultado un error en Chrome y una página vacía en Firefox.

[ActionName("display-file")] 
public virtual ActionResult DisplayFile (Guid fileId, string fileName) 
{ 
    var file = _repos.GetFileInfo(fileId); 
    if (file != null) 
    { 
     Response.AddHeader("Content-Disposition", 
      string.Format("inline; filename={0}", file.Name)); 
     return File(file.Content, file.MimeType, file.Name); 
    } 
} 

[ActionName("download-file")] 
public virtual ActionResult DownloadFile (Guid fileId, string fileName) 
{ 
    var file = _repos.GetFileInfo(fileId); 
    if (file != null) 
    { 
     return File(file.Content, file.MimeType, file.Name); 
    } 
} 

Éstos son los 2 cabeceras enviadas al navegador para la acción de la pantalla:

Content-Disposition: inline; filename=name-of-my-file.pdf 
Content-Disposition: attachment; filename="name-of-my-file.pdf" 

He intentado cambiar mi cabecera content-disposition personalizada para envolver el nombre de archivo entre comillas dobles, pero aún así envió 2 encabezados para el navegador. También traté de eliminar el encabezado Content-Disposition antes de agregar el personalizado, pero parece que el encabezado del archivo adjunto se agrega después de que se devuelve FileContentResult.

Este código solía funcionar. Ejecuté una prueba ayer y noté que ya no funciona en Chrome o Firefox. Esto podría deberse a las actualizaciones en los navegadores. IE8 y Safari aún abren el archivo correctamente.

actualización

Gracias de nuevo Darin, que son correctas. De hecho, utilizamos este enfoque debido a another question you answered.

Un poco más de información acerca de cómo esto se resolvió en última instancia, por nuestra parte, tenemos una ruta personalizada para el enlace de archivo de pantalla:

context.MapRoute(null, 
    "path/to/display-file-attachment/{fileId}/{fileName}", 
    new 
    { 
     area = "AreaName", 
     controller = "ControllerName", 
     action = "DisplayFile", 
    } 
); 

El hipervínculo de la página pasa el nombre del archivo para el método de acción a través el parámetro de ruta, por lo que ya es parte de la URL. Por lo tanto, no fue necesario agregar un encabezado de disposición de contenido personalizado para que el nombre del archivo coincida con el del sistema cuando el usuario decidió descargarlo (al hacer clic en el icono Guardar en el visualizador de PDF del navegador). Así que sólo utilizamos esto:

[ActionName("display-file")] 
public virtual ActionResult DisplayFile (Guid fileId, string fileName) 
{ 
    var file = _repos.GetFileInfo(fileId); 
    if (file != null) 
    { 
     // no custom content-disposition header, and no 3rd fileName argument 
     return File(file.Content, file.MimeType); 
    } 
} 
+0

Firefox y Chrome de hecho se han vuelto más estrictas en el manejo de cabeceras Content-Disposition. –

+0

@JulianReschke, ¿podría explicar los caracteres que no son ASCII? Todavía no hemos probado esto con caracteres Unicode en nombres de archivo. – danludwig

+0

para nombres que no sean ASCII en C-D para "funcionar" en todos los navegadores, los servidores actualmente necesitan hacer sniffing User-Agent. Ver http://greenbytes.de/tech/tc2231/ y http://greenbytes.de/tech/webdav/rfc6266.html. Tengo mis dudas de que ASP.net lo haga bien, pero me encantaría saber lo contrario. –

Respuesta

24

Cuando se utiliza la sobrecarga File(byte[] contents, string mimeType, string fileName) una cabecera Content-Disposition se añade automáticamente a la respuesta con attachment, por lo que no es necesario añadir una segunda vez. Para inline se puede utilizar la siguiente sobrecarga File(byte[] contents, string mimeType) y añadir manualmente la cabecera Content-Disposition:

[ActionName("display-file")] 
public virtual ActionResult DisplayFile(Guid fileId) 
{ 
    var file = _repos.GetFileInfo(fileId); 
    var cd = new ContentDisposition 
    { 
     Inline = true, 
     FileName = file.Name 
    }; 
    Response.AddHeader("Content-Disposition", cd.ToString()); 
    return File(file.Content, file.MimeType); 
} 

[ActionName("download-file")] 
public virtual ActionResult DownloadFile(Guid fileId) 
{ 
    var file = _repos.GetFileInfo(fileId); 
    return File(file.Content, file.MimeType, file.Name); 
} 
+0

Me la ganaste, estaba a punto de publicar una respuesta similar. Omitir el tercer argumento fileName funciona. Sin embargo, la disposición de contenido no necesita ser agregada en nuestro caso. Simplemente 'return File (file.Content, file.MimeType);' funciona, ya que el nombre del archivo se deriva de una ruta personalizada. – danludwig

+0

Bueno, con suerte, el framework hace lo correcto con respecto a los caracteres que no son ASCII ... –

+0

@JulianReschke, ¿qué caracteres no ASCII? El marco no hace nada al respecto. Tu decides. Si está hablando de caracteres que no son ASCII en los nombres de los archivos, entonces sí, es horrible PITA. Pero no es algo de lo que podría esperar que el marco lo ayude. Es simplemente algo implementado de manera diferente por diferentes navegadores. En resumen, es algo que no se debe usar :-) –

Cuestiones relacionadas