¿Por qué son los archivos .docx siendo corrompidos cuando se descarga desde una página ASP.NET?

StackOverflow https://stackoverflow.com/questions/2477564

  •  21-09-2019
  •  | 
  •  

Pregunta

Tengo este código siguiente para traer archivos adjuntos de página para el usuario:

private void GetFile(string package, string filename)
{
    var stream = new MemoryStream();

    try
    {
        using (ZipFile zip = ZipFile.Read(package))
        {
            zip[filename].Extract(stream);
        }
    }
    catch (System.Exception ex)
    {
        throw new Exception("Resources_FileNotFound", ex);
    }

    Response.ClearContent();
    Response.ClearHeaders();
    Response.ContentType = "application/unknown";

    if (filename.EndsWith(".docx"))
    {
        Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    }

    Response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
    Response.BinaryWrite(stream.GetBuffer());
    stream.Dispose();
    Response.Flush();
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

El problema es que todos los archivos soportados funciona correctamente (JPG, GIF, PNG, PDF, DOC, etc), pero los archivos .docx, cuando descargado, están dañados y necesitan ser fijado por la Oficina con el fin de ser abierto.

Al principio no sabía si el problema estaba en descomprimir el archivo zip que contiene el .docx, así que en vez de poner el archivo de salida sólo en la respuesta, lo guardé en primer lugar, y el archivo abierto con éxito, por lo que sabe que el problema debe estar en la escritura de respuesta.

¿Sabe lo que puede estar pasando?

¿Fue útil?

Solución

También encontré con este problema y, de hecho encontré la respuesta aquí: http: // www .aspmessageboard.com / showthread.php? t = 230778

Resulta que el formato docx necesita tener Response.End () inmediatamente después de la Response.BinaryWrite.

Otros consejos

Al almacenar un archivo binario en SQL Server, tenga en cuenta que un archivo se rellena a la palabra sitio limítrofe más cercano, por lo que puede llegar a tener un byte adicional agregado a un archivo. La solución es almacenar el tamaño del archivo original en el PP cuando vaya a guardar el archivo, y el uso que de la longitud que necesita ser pasado a la función de escritura del objeto Stream. "Stream.Write (bytes (), 0, longitud)". Esta es la ÚNICA manera fiable de conseguir el tamaño correcto de archivos, lo cual es muy importante para Office 2007 y de seguridad de archivos, que no permita que los caracteres adicionales a estar en el extremo de ellos (la mayoría de los otros tipos de archivo como jpg de no les importa).

No use stream.GetBuffer() porque devuelve la matriz de memoria intermedia que podría contener bytes no utilizados. Utilice stream.ToArray() lugar. Además, ¿ha intentado llamar stream.Seek(0, SeekOrigin.Begin) antes de escribir algo?

Mejores Saludos, Oliver Hanappi

Por lo que vale la pena, también me encontré con el mismo problema que aparece aquí. Para mí, la cuestión era en realidad no con el código carga el código de descarga:

    Public Sub ImportStream(FileStream As Stream)
        'Use this method with FileUpload.PostedFile.InputStream as a parameter, for example.
        Dim arrBuffer(FileStream.Length) As Byte
        FileStream.Seek(0, SeekOrigin.Begin)
        FileStream.Read(arrBuffer, 0, FileStream.Length)
        Me.FileImage = arrBuffer
    End Sub

En este ejemplo, el problema es Declaro la arrBuffer matriz de bytes con un tamaño de un byte demasiado grande. Este byte nulo se guarda la imagen del archivo de la base de datos con y reproducido de descarga. El código corregido sería:

        Dim arrBuffer(FileStream.Length - 1) As Byte

También para mi código de referencia HttpResponse es el siguiente:

                context.Response.Clear()
                context.Response.ClearHeaders()
                'SetContentType() is a function which looks up the correct mime type
                'and also adds and informational header about the lookup process...
                context.Response.ContentType = SetContentType(objPostedFile.FileName, context.Response)
                context.Response.AddHeader("content-disposition", "attachment;filename=" & HttpUtility.UrlPathEncode(objPostedFile.FileName))
                'For reference: Public Property FileImage As Byte()
                context.Response.BinaryWrite(objPostedFile.FileImage)
                context.Response.Flush()

Si se utiliza el método anterior que utiliza response.Close (), Gestores de descargas tales como IE10 dirán 'no puede descargar el fichero' debido a que las longitudes de bytes no coinciden con las cabeceras. Consulte la documentación. NO utilice response.Close. SIEMPRE. Sin embargo, utilizando el verbo CompeteRequest solos no se apaga la escritura de bytes a la corriente ouput lo que las aplicaciones basadas en XML como por ejemplo Word 2007 verán la docx como está dañado. En este caso, romper la regla de no usar NUNCA Response.End. El siguiente código resuelve ambos problemas. Sus resultados pueden variar.

        '*** transfer package file memory buffer to output stream
        Response.ClearContent()
        Response.ClearHeaders()
        Response.AddHeader("content-disposition", "attachment; filename=" + NewDocFileName)
        Me.Response.ContentType = "application/vnd.ms-word.document.12"
        Response.ContentEncoding = System.Text.Encoding.UTF8
        strDocument.Position = 0
        strDocument.WriteTo(Response.OutputStream)
        strDocument.Close()
        Response.Flush()
        'See documentation at http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx
        HttpContext.Current.ApplicationInstance.CompleteRequest() 'This is the preferred method
        'Response.Close() 'BAD pattern. Do not use this approach, will cause 'cannot download file' in IE10 and other download managers that compare content-Header to actual byte count
        Response.End() 'BAD Pattern as well. However, CompleteRequest does not terminate sending bytes, so Word or other XML based appns will see the file as corrupted. So use this to solve it.

@Cesar: está utilizando response.Close -> se puede probar con IE 10? apuesto a que no funciona (cantidad de bytes no coinciden)

Todo se ve bien. Mi única idea es tratar de llamar a Dispose en su torrente después de llamar Response.Flush en vez de antes, por si acaso los bytes no están escritos en su totalidad antes de enjuagar.

Tome un aspecto un siguiente: escritura MemoryStream al objeto respuesta

Yo tenía el mismo problema y la única solución que funcionó para mí fue:

    Response.Clear();
    Response.ContentType = "Application/msword";
    Response.AddHeader("Content-Disposition", "attachment; filename=myfile.docx");
    Response.BinaryWrite(myMemoryStream.ToArray());
    // myMemoryStream.WriteTo(Response.OutputStream); //works too
    Response.Flush();
    Response.Close();
    Response.End();

Yo tenía el mismo problema, mientras que intento abrir .docx y .xlsx documentos. Resuelvo el problema mediante la definición de los caches a ServerAndPrivate en lugar de NoCache

no es mi método para llamar documento:

public void ProcessRequest(HttpContext context)

 {


       var fi = new FileInfo(context.Request.Path);
        var mediaId = ResolveMediaIdFromName(fi.Name);
        if (mediaId == null) return;

        int mediaContentId;
        if (!int.TryParse(mediaId, out mediaContentId)) return;

        var media = _repository.GetPublicationMediaById(mediaContentId);
        if (media == null) return;

        var fileNameFull = string.Format("{0}{1}", media.Name, media.Extension);
        context.Response.Clear();
        context.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", fileNameFull));            
        context.Response.Charset = "";
        context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
        context.Response.ContentType = media.ContentType;
        context.Response.BinaryWrite(media.Content);
        context.Response.Flush();          
        context.Response.End();          
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top