This project has moved. For the latest updates, please go here.
9
Vote

using InsertDocument gives corrupted documents

description

Hi,
 
Given the following situation: I have a docx document which i load into the DocX library using a Stream, everything works well untill this point. Now i want to use the "InsertDocument" method which is provided by the DocX class itself. When i try to insert a document (also a Stream) and later on save the document, everything seems to work well, except for the moment i try to open the document. It throws me an error that to document is corrupt. Word 2010 allows you to open the document and repair it. But as you all would agree this is not really a situation which will be accepted by the end user!
 
Code example:
 
// Loading the file
this._document = Novacode.DocX.Load(item.File.OpenBinaryStream());
 
// Loading the 2nd document to insert inside this._document
using (Novacode.DocX doc = Novacode.DocX.Load(templateItem.File.OpenBinaryStream()))
{
// Filling some document specific CustomProperties..
doc.AddCustomProperty(new Novacode.CustomProperty("doc_prop_1", "test"));
 
_document.InsertDocument(doc);
}
 
// Save the document
using (MemoryStream ms = new MemoryStream())
{
this._document.SaveAs(ms);
// Here i store the file somewhere inside SharePoint 2010.
}
 
 
Last but not least: Is there also a possiblity whichs allows me to insert a document at a specific location?
 
Please do not hestistate to ask me when you need more information!
 
With kind regards,
Marcel Andeweg

comments

MadBoy wrote Feb 8, 2012 at 3:51 PM

It's been known problem with Merging multiple documents. It's been reported but never fixed. Cathal says it's very basic support, and very young so most likely all we can do is wait for him to actually make it priority. Until then I'm using Interop merging. Not best but there's no way for DocX to do this until fixed. If you want the code let me know.

Andeweg86 wrote Feb 8, 2012 at 4:01 PM

Hi MadBoy,

Thanks for your quick reply! I am very interested in some code examples for the Interop merging!

Thanks in advance.

MadBoy wrote Feb 8, 2012 at 4:27 PM

It doesn't give perfect merging (some additional spaces/lines here and there) but it works fine.

I call it like that:
public static void documentsMerge(object fileName, List<string> arrayList) {
        MsWord.Merge(arrayList, (string) fileName, true);
}

region

using System;
using System.Collections.Generic;
using Microsoft.Office.Interop.Word;

endregion

namespace KeithRull.Utilities.OfficeInterop {
public class MsWord {
    /// <summary>
    ///   This is the default Word Document Template file. I suggest that you point this to the location
    ///   of your Ms Office Normal.dot file which is usually located in your Ms Office Templates folder.
    ///   If it does not exist, what you could do is create an empty word document and save it as Normal.dot.
    /// </summary>
    private static string defaultWordDocumentTemplate = @"C:\Template.dotx";
    /// <summary>
    ///   A function that merges Microsoft Word Documents that uses the default template
    /// </summary>
    /// <param name = "filesToMerge">An array of files that we want to merge</param>
    /// <param name = "outputFilename">The filename of the merged document</param>
    /// <param name = "insertPageBreaks">Set to true if you want to have page breaks inserted after each document</param>
    public static void Merge(List<string> filesToMerge, string outputFilename, bool insertPageBreaks) { Merge(filesToMerge, outputFilename, insertPageBreaks, defaultWordDocumentTemplate); }
    /// <summary>
    ///   A function that merges Microsoft Word Documents that uses a template specified by the user
    /// </summary>
    /// <param name = "filesToMerge">An array of files that we want to merge</param>
    /// <param name = "outputFilename">The filename of the merged document</param>
    /// <param name = "insertPageBreaks">Set to true if you want to have page breaks inserted after each document</param>
    /// <param name = "documentTemplate">The word document you want to use to serve as the template</param>
    public static void Merge(List<string> filesToMerge, string outputFilename, bool insertPageBreaks, string documentTemplate) {
        object defaultTemplate = documentTemplate;
        object missing = Type.Missing;
        object pageBreak = WdBreakType.wdSectionBreakNextPage;
        object outputFile = outputFilename;
        // Create  a new Word application
        _Application wordApplication = new Application();
        try {
            // Create a new file based on our template
            Document wordDocument = wordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing);
            // Make a Word selection object.
            Selection selection = wordApplication.Selection;
            //Count the number of documents to insert;
            int documentCount = filesToMerge.Count;
            //A counter that signals that we shoudn't insert a page break at the end of document.
            int breakStop = 0;
            // Loop thru each of the Word documents
            foreach (string file in filesToMerge) {
                breakStop++;
                // Insert the files to our template
                selection.InsertFile(file, ref missing, ref missing, ref missing, ref missing);
                //Do we want page breaks added after each documents?
                if (insertPageBreaks && breakStop != documentCount) {
                    selection.InsertBreak(ref pageBreak);
                }
            }
            // Save the document to it's output file.
            wordDocument.SaveAs(ref outputFile, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
            // Clean up!
            wordDocument = null;
        } catch (Exception ex) {
            //I didn't include a default error handler so i'm just throwing the error
            throw ex;
        } finally {
            // Finally, Close our Word application
            wordApplication.Quit(ref missing, ref missing, ref missing);
        }
    }
}
}

wrote Mar 22, 2012 at 10:17 PM

MadBoy wrote Apr 12, 2012 at 9:27 AM

Hello Marcel, please check the newest code base. The issue seems to be fixed. Let me know.

wrote May 4, 2012 at 8:23 PM

dtimms wrote May 9, 2012 at 10:14 PM

I'm also facing this issue... hoping for some workaround that isn't word interop

wrote May 9, 2012 at 10:14 PM

MadBoy wrote May 9, 2012 at 11:00 PM

Dttims can you check newest version? Take the source and compile it yourself and let us know? It's been fixed in couple of last sources but the binary provided doesn't have it yet implemented so if you can check that it would be cool.

wrote May 10, 2012 at 12:23 PM

wrote Jul 17, 2012 at 9:30 PM

wrote Aug 6, 2012 at 9:55 PM

wrote Feb 22, 2013 at 1:34 AM

HansWursti wrote Feb 6, 2014 at 4:05 PM

I failed using InsertDocument too. Everytime i opened the resulting doc in Word it says broken.
Here is my Workaround...
Use the document to Insert as Template! ...Load it, clean it and than you can use InsertDocument on that Template.
Using stream = New IO.MemoryStream(docToInsert)
  Using doc = DocX.Load(stream)
     For Each para In doc.Paragraphs
         para.Remove(False)
     Next
     doc.SaveAs(fileName)
  End Using
End Using

Using docContainer = DocX.Load(fileName)
  docContainer.InsertDocument(docToInsert)
  docContainer.SaveAs(....)
End Using

wrote Oct 26, 2015 at 12:37 PM

lckuiper wrote Oct 26, 2015 at 12:39 PM

wrote Nov 23, 2015 at 9:38 AM

BoucherS wrote Apr 21 at 6:39 PM

Hi,

Should be fixed with https://docx.codeplex.com/workitem/13694.

InsertDocument method has an "append' argument, true by default. When true, document is added at the end. If False, document is added at the beginning.