Search code examples
c#memorystreamwordprocessingml

Open XML SDK Word processing header part FeedData throws "MEMORY STREAM IS NOT EXPANDABLE" error


I have a function that is suppose to copy an existing header from a given .docx file, edit the copied header and add original as first page header and copied as even page header.

 public byte[] AddExtraHeader(byte[] report)
 {
    using (WordprocessingDocument
    wdDoc = WordprocessingDocument.Open(new MemoryStream(report), true))
    {
        MainDocumentPart mainPart = wdDoc.MainDocumentPart;
        var settingsPart = wdDoc.MainDocumentPart.DocumentSettingsPart;
        var element = new Settings(new TitlePage());
        element.Save(settingsPart);

        //Get existing header
        DocumentFormat.OpenXml.Packaging.HeaderPart oldHeader = mainPart.HeaderParts.FirstOrDefault();

        // Create a new header part.
        DocumentFormat.OpenXml.Packaging.HeaderPart newHeader = mainPart.AddNewPart<HeaderPart>();

        // Get Id of the headerPart.
        string rIdOld = mainPart.GetIdOfPart(oldHeader);
        string rIdNew = mainPart.GetIdOfPart(newHeader);

        if (oldHeader != null)
        {
            newHeader.FeedData(oldHeader.GetStream()); //Error right here
        }

        //Gets the text in headers
        foreach (var currentText in newHeader.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
        {
           currentText.Text = currentText.Text.Replace("trecio", "");
        }
        // Get SectionProperties and Replace HeaderReference with new Id.
        IEnumerable<DocumentFormat.OpenXml.Wordprocessing.SectionProperties> sectPrs =
        mainPart.Document.Body.Elements<SectionProperties>();
        foreach (var sectPr in sectPrs)
        {
            // Delete existing references to headers.
            sectPr.RemoveAllChildren<HeaderReference>();

            // Create the new header reference node.
            sectPr.PrependChild<HeaderReference>(new HeaderReference() { Type = HeaderFooterValues.First, Id = rIdOld});
            sectPr.PrependChild<HeaderReference>(new HeaderReference() { Type = HeaderFooterValues.Even, Id = rIdNew });
                }
            }
            return report;
        }

But when I try to feed data from the original header to the newly created copy I get an

MEMORY STREAM IS NOT EXPANDABLE

Error. I tried to copy the example from https://learn.microsoft.com/en-us/office/open-xml/how-to-replace-the-header-in-a-word-processing-document

public static void AddHeaderFromTo(string filepathFrom, string filepathTo)
{
    // Replace header in target document with header of source document.
    using (WordprocessingDocument 
            wdDoc = WordprocessingDocument.Open(filepathTo, true))
    {
         MainDocumentPart mainPart = wdDoc.MainDocumentPart;
            
         // Delete the existing header part.
         mainPart.DeleteParts(mainPart.HeaderParts);

         // Create a new header part.
         DocumentFormat.OpenXml.Packaging.HeaderPart headerPart = 
         mainPart.AddNewPart<HeaderPart>();
            
         // Get Id of the headerPart.
         string rId = mainPart.GetIdOfPart(headerPart);
            
         // Feed target headerPart with source headerPart.
          using (WordprocessingDocument wdDocSource = 
                WordprocessingDocument.Open(filepathFrom, true))
          {
                DocumentFormat.OpenXml.Packaging.HeaderPart firstHeader =
                wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();

                wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();

                if (firstHeader != null)
                {
                    headerPart.FeedData(firstHeader.GetStream()); // No error here
            }
         }

            // Get SectionProperties and Replace HeaderReference with new Id.
            IEnumerable<DocumentFormat.OpenXml.Wordprocessing.SectionProperties> sectPrs = 
        mainPart.Document.Body.Elements<SectionProperties>();
            foreach (var sectPr in sectPrs)
            {
                // Delete existing references to headers.
                sectPr.RemoveAllChildren<HeaderReference>();

                // Create the new header reference node.
                sectPr.PrependChild<HeaderReference>(new HeaderReference() { Id = rId });
            }    
        }
    }

The example works fine for me and gets the desired result, but I can't tell the difference between my FeedData and examples FeedData.

Am I missing something?


Solution

  • Based on Memory stream is not expandable answer

    If you create a MemoryStream over a pre-allocated byte array, it can't expand (ie. get longer than the size you specified when you started).

    So the solution is to create a memory stream based on the byte array, then create a new empty memory stream and copy the contents of the first memory stream to the second one and then work with the second memory stream, like so:

    var ms = new MemoryStream();
    var reportStream = new MemoryStream(report);
    reportStream.CopyTo(ms);
    using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(ms, true))
         {
         // rest of the code
         }