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

1

8

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

Arillode answered 6/2, 2017 at 23:58 Comment(3)
I know this is old but did you understand why attaching the template file was necessary? What if I skip that step?Willie
@Willie It is not necessary. I needed it because I had a base template that contained some custom created styles that the result documents required. But you can as well open directly a .docx file. The code should work the same.Arillode
Thanks! Even I have a base template (.dotx) with custom styles.Willie
T
4

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.

Thaddeusthaddus answered 9/2, 2017 at 19:53 Comment(1)
Thanks for the answer, Michael. It was late and I din't see it. You are right, by exiting the using block of the document, Open XML is saving the changes and also closing/disposing the unmanaged resources. So I basically tried to open something that was not completely saved.Arillode

© 2022 - 2024 — McMap. All rights reserved.