Streaming In Memory Word Document using OpenXML SDK w/ASP.NET results in "corrupt" document

20,115

Solution 1

Use CopyTo instead, there is a bug in WriteTo which makes it fail to write the entire content of the buffer when the target stream does not support writing everything in one go.

Solution 2

As variant for .NET Framework 3.5 and lower. This version of framework haven't method CopyTo in class Stream. Therefore, method WriteTo is replaced by next code:

byte[] arr = documentStream.ToArray();
fileStream.Write(arr, 0, arr.Length);

Example was found by http://blogs.msdn.com/b/mcsuksoldev/archive/2010/04/09/creating-a-new-microsoft-word-document-from-a-template-using-openxml.aspx

Solution 3

I believe your ContentType value is incorrect; that is for Word 97 - 2003 format. Change it to:

application/vnd.openxmlformats-officedocument.wordprocessingml.document

and see if that fixes the problem.

Solution 4

(This is using OpenXML SDK v 2.10.0 and .Net Core v2.2)

I know this has been answered but I wanted to throw out another option. It is correct that trying to send a stream back in File() like below will result in a corrupt document:

                MemoryStream updateStream = new MemoryStream();
                wordDocument.Save();
                wordDocument.Clone(updateStream);


                return File(updateStream, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");

`

A super simple alternative/workaround would be to simply convert your stream to a byte[] like below and it will result in a working word docx

                MemoryStream updateStream = new MemoryStream();
                wordDocument.Save();
                wordDocument.Clone(updateStream);


                return File(updateStream.ToArray(), "application/vnd.openxmlformats-officedocument.wordprocessingml.document");

Solution 5

I copied and pasted your code and noticed that the :"wordDocument.close();" clausule was missing, added it and it worked (I did it in Asp.NET MVC witing an action)

Share:
20,115
Ta01
Author by

Ta01

I believe that our kind is cursed. We are cursed to lose our greatest warriors; our most noble heroes; our most gifted scholars.

Updated on July 09, 2022

Comments

  • Ta01
    Ta01 almost 2 years

    I am unable to stream a word document that I create on the fly down to the browser. I am constantly getting a message from Microsoft Word that the document is corrupt.

    When I run the code via a Console Application and take ASP.NET out of the picture, the document is generated correctly with no problems. I believe everything centers around writing the file down.

    Here is my code:

    using (MemoryStream mem = new MemoryStream())
    {
        // Create Document
        using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(mem, WordprocessingDocumentType.Document, true))
        {
            // Add a main document part. 
            MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
    
            new Document(new Body()).Save(mainPart);
    
            Body body = mainPart.Document.Body;
            body.Append(new Paragraph(new Run(new Text("Hello World!"))));
    
            mainPart.Document.Save();
            // Stream it down to the browser
    
            // THIS IS PROBABLY THE CRUX OF THE MATTER <---
            Response.AppendHeader("Content-Disposition", "attachment;filename=HelloWorld.docx");
            Response.ContentType = "application/vnd.ms-word.document";
            mem.WriteTo(Response.OutputStream);
            Response.End();
        }
    }
    

    I have looked at a lot of links – but nothing quite works. I lot of people use MemoryStream.WriteTo and some use BinaryWrite – at this point I'm not sure what the correct way is. Also I've tried the longer content type, i.e. application/vnd.openxmlformats-officedocument.wordprocessingml.document but no luck.

    Some screenshots – even if you try to recover you get the same "parts are missing or invalid"

    Solution for those who stumble on this question:

    Within the using directive of the WordProcessingDocument, you must call:

    wordDocument.Save();
    

    Also to correctly stream the MemoryStream, use this in the outer using block:

    Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    Response.AppendHeader("Content-Disposition", "attachment;filename=HelloWorld.docx");
    mem.Position = 0;
    mem.CopyTo(Response.OutputStream);
    Response.Flush();
    Response.End();
    

    enter image description here enter image description here