Search code examples
c#openxml

Trying to create an in memory Word Doc with OpenXml says it's corrupt


I've built an ActionResult to output data to a Word Document. I get no errors at compile or runtime, but when trying to open the file I get the message: 'We're sorry, We can't open filename.docx because we found a problem with its contents.'.

Here's what I'm trying to do:

public override void ExecuteResult(ControllerContext context)
{
    //Create a response stream to create and write the Excel file
    HttpContext curContext = HttpContext.Current;
    curContext.Response.Clear();
    curContext.Response.AddHeader("content-disposition", "attachment;filename=text.docx");
    curContext.Response.Charset = "";
    curContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    curContext.Response.ContentType = "application/vnd.ms-word";

    //Write the stream back to the response
    var ms = new MemoryStream();

    var repData = "<b>Mark's Test Book: With a Special Sub Title</b><br /><br /><b>Chapter: Chapter Title 1: Chapter Title sub</b><br /><br />";

    Document.CreateAndAddHtmlToWordprocessingStream(ms, repData);

    curContext.Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);

    curContext.Response.End();

}

The static method is as follows:

public static void CreateAndAddHtmlToWordprocessingStream(Stream stream, string inputBody)
{
    // Open a WordProcessingDocument based on a stream.
    WordprocessingDocument wordprocessingDocument =
        WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document);

    // Add a main document part. 
    MainDocumentPart mainPart = wordprocessingDocument.AddMainDocumentPart();

    // Create the document structure.
    mainPart.Document = new DocumentFormat.OpenXml.Wordprocessing.Document();

    // Create the document body.
    mainPart.Document.AppendChild(new Body());

    var ms = new MemoryStream(System.Text.Encoding.Default.GetBytes("<html><head></head><body style=\"font-family:'Calibri';\">" + inputBody + "</body></html>"));

    var altChunkId = "id";
    var formatImportPart = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html, altChunkId);

    formatImportPart.FeedData(ms);

    var altChunk = new AltChunk { Id = altChunkId };

    mainPart.Document.Body.Append(altChunk);

    mainPart.Document.Save();

    // Close the document handle.
    wordprocessingDocument.Close();

    // Caller must close the stream.
}

I've looked at these two posts, but didn't find anything that helped:

C# return memory stream from OpenXML resulting to a corrupted word file

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


Solution

  • ms.GetBuffer() will return the automatically managed and sized buffer. This will start with the data you have written, but may contain extra \0 bytes at the end in the eventuality you continue to .Write().

    To return a MemoryStream, you can use either of the following:

    ms.Position = 0;
    ms.CopyTo(curContext.Response.OutputStream);
    

    or:

    var msResult = ms.ToArray();
    curContext.Response.OutputStream.Write(msResult, 0, msResult.Length);