Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open XML SDK - Create docx from template (dotx) using MemoryStream as docx holder

I am trying to create a .docx file from a word template (.dotx), using OpenXML 2.5 library. More exactly, I'm trying to follow this , but I want to open the document using a MemoryStream and not the path to the file.

So in the link above, the approach is this: Copy the template file in a new file on disk. Open the new file as a WordProcessingDocument, change its type to Document and add a reference to the template (I'm not sure of why is this necessary ...)

What I need is. Get my template from the DB as byte array. Copy the array to a stream and open it as a WordProcessingDocument. Then do the same thing as above. I don't want to use temporary files on disk and so on. What I don;t understand is why should I reference the template file in the new document (Actually, inspecting the xml files in the docx archive, it just adds a xml node containing the name of the template... why?)

Now, my problem is that if I use a MemoryStream and not a physical path to the file, the resulting docx is corrupted. I'm getting "Microsoft office cannot open this file because some parts are missing or invalid". If I use temporary disk files, it works. Why is this happening?

Simplified, my code looks like this:

byte[] result = null;
byte[] templateBytes = System.IO.File.ReadAllBytes("template.dotx");
using (MemoryStream templateStream = new MemoryStream())
{
    templateStream.Write(templateBytes, 0, (int)templateBytes.Length);

    using (WordprocessingDocument doc = WordprocessingDocument.Open(templateStream, true))
    {
        doc.ChangeDocumentType(WordprocessingDocumentType.Document);
        var mainPart = doc.MainDocumentPart;

        //Here I should create an AttachedTemplate object and assign a relationship id to it, which also implies
        //setting a "reference" to the template ? I'm not using files so there's nothing to "reference" anyway
        // If it's doing more than just putting a visual reference to the template file, then why limit the way of referencing the template
        // only by using the Uri to the file? Please take a look at the above link to see what I'm referring to.

        //Write some text in the file ....
        mainPart.Document.Save();

        File.WriteAllBytes("Result.docx", templateStream.ToArray());
    }
}

This gets me a corrupted docx file. If I switch from MemoryStream to opening the new docx file from disk (using the other constructor of the WordProcessingDocument class), it works. I'm not doing something wrong (like trying to write the result to the file after disposing the memory stream), so it should give me the same result.

What is wrong with my code?

Thanks

like image 921
darkdante Avatar asked Feb 06 '17 23:02

darkdante


1 Answers

If you take the last line of your code File.WriteAllBytes out of the inner using block, it should work correctly. Just put that line right before the closing brace of the outer using block.

like image 74
Michael Daniloff Avatar answered Nov 11 '22 15:11

Michael Daniloff