After we do word merge with Asponse we need to combine all the documents into one, and also we need to preserve page numbers.
The code I have is working perfectly, except when we reach about 100 documents to join, we get a 'System.OutofMemoryException'
I executed the same thing on my development computer, and while it's executing the IIS worker process w3wp.exe peaks at about 2.2 Gbytes of memory, it takes a long time to process, but it finishes without errors, and returns the combined document. The end document is 1.1 MBytes, and over 150 pages... Why does it take over 2.2 GBytes of ram to process if the document is only 1.1 MBytes?
The same process (same documents) on the server returns the "out of memory" error.
Any idea how to make it use less memory?
This is the code I am using:
The first function is writen by me, the rest are copied and pasted from your forum.
Private Sub cmd_CombineForms() Dim TL As cSelectTemplateList = CType(Session("SelectForms_TemplateList"), cSelectTemplateList) Dim GeneratedPath As String = CType(Session("GeneratedPath"), String) Dim FilesAdded As Boolean = False Dim FirstDoc As Boolean = Trueimpersonator.BeginImpersonation() ' impersonate user to have access to folders on the network Dim doc As Aspose.Words.Document = Nothing For Each TI As cSelectTemplateList.cTemplateInfo In TL.TemplateList If TI.GeneratedFileName.Length() > 0 AndAlso System.IO.File.Exists(GeneratedPath & TI.GeneratedFileName) Then If FirstDoc Then doc = New Aspose.Words.Document(GeneratedPath & TI.GeneratedFileName) FirstDoc = False Else Dim append_doc As Aspose.Words.Document = New Aspose.Words.Document(GeneratedPath & TI.GeneratedFileName) append_doc.FirstSection.HeadersFooters.LinkToPrevious(False) append_doc.FirstSection.PageSetup.SectionStart = SectionStart.NewPage append_doc.FirstSection.PageSetup.RestartPageNumbering = True append_doc.FirstSection.PageSetup.PageStartingNumber = 1 doc.AppendDocument(append_doc, ImportFormatMode.KeepSourceFormatting) append_doc = Nothing End If FilesAdded = True End If Next If FilesAdded AndAlso doc IsNot Nothing Then Response.ContentType = "application/vnd.ms-word.document" Dim FileName As String = "" If Me.txtPolicyNumber.Text.Trim().Length() = 0 Then FileName = "Default.docx" Else FileName = Split(Me.txtPolicyNumber.Text.Trim(), " ")(0) & ".docx" End If Response.AddHeader("content-disposition", "attachment;filename=" & Context.Server.HtmlEncode(FileName)) ConvertNumPageFieldsToPageRef(doc) doc.UpdatePageLayout() doc.Save(Response.OutputStream, Aspose.Words.SaveFormat.Docx) Response.Flush() Response.End() End If impersonator.EndImpersonation() doc = Nothing
End Sub
‘’’
‘’’ Replaces all NUMPAGES fields in the document with PAGEREF fields. The replacement field displays the total number
‘’’ of pages in the sub document instead of the total pages in the document.
‘’’
‘’’ The combined document to process
Private Shared Sub ConvertNumPageFieldsToPageRef(ByVal doc As Document)
’ This is the prefix for each bookmark which signals where page numbering restarts.
’ The underscore “_” at the start inserts this bookmark as hidden in MS Word.
Const bookmarkPrefix As String = “_SubDocumentEnd”
’ Field name of the NUMPAGES field.
Const numPagesFieldName As String = “NUMPAGES”
’ Field name of the PAGEREF field.
Const pageRefFieldName As String = “PAGEREF”' Create a new DocumentBuilder which is used to insert the bookmarks and replacement fields. Dim builder As New DocumentBuilder(doc) ' Defines the number of page restarts that have been encountered and therefore the number of "sub" documents ' found within this document. Dim subDocumentCount As Integer = 0 ' Iterate through all sections in the document. For Each section As Section In doc.Sections ' This section has it's page numbering restarted so we will treat this as the start of a sub document. ' Any PAGENUM fields in this inner document must be converted to special PAGEREF fields to correct numbering. If section.PageSetup.RestartPageNumbering Then ' Don't do anything if this is the first section in the document. This part of the code will insert the bookmark marking ' the end of the previous sub document so therefore it is not applicable for first section in the document. If (Not section.Equals(doc.FirstSection)) Then ' Get the previous section and the last node within the body of that section. Dim prevSection As Section = CType(section.PreviousSibling, Section) Dim lastNode As Node = prevSection.Body.LastChild ' Use the DocumentBuilder to move to this node and insert the bookmark there. ' This bookmark represents the end of the sub document. builder.MoveTo(lastNode) builder.StartBookmark(bookmarkPrefix & subDocumentCount) builder.EndBookmark(bookmarkPrefix & subDocumentCount) ' Increase the subdocument count to insert the correct bookmarks. subDocumentCount += 1 End If End If ' The last section simply needs the ending bookmark to signal that it is the end of the current sub document. If section.Equals(doc.LastSection) Then ' Insert the bookmark at the end of the body of the last section. ' Don't increase the count this time as we are just marking the end of the document. Dim lastNode As Node = doc.LastSection.Body.LastChild builder.MoveTo(lastNode) builder.StartBookmark(bookmarkPrefix & subDocumentCount) builder.EndBookmark(bookmarkPrefix & subDocumentCount) End If ' Iterate through each NUMPAGES field in the section and replace the field with a PAGEREF field referring to the bookmark of the current subdocument ' This bookmark is positioned at the end of the sub document but does not exist yet. It is inserted when a section with restart page numbering or the last ' section is encountered. Dim nodes() As Node = section.GetChildNodes(Aspose.Words.NodeType.FieldStart, True).ToArray() For Each fieldStart As FieldStart In nodes If fieldStart.FieldType = FieldType.FieldNumPages Then ' Get the field code. Dim fieldCode As String = GetFieldCode(fieldStart) ' Since the NUMPAGES field does not take any additional parameters we can assume the remaining part of the field ' code after the fieldname are the switches. We will use these to help recreate the NUMPAGES field as a PAGEREF field. Dim fieldSwitches As String = fieldCode.Replace(numPagesFieldName, "").Trim() ' Inserting the new field directly at the FieldStart node of the original field will cause the new field to ' not pick up the formatting of the original field. To counter this insert the field just before the original field Dim previousNode As Node = fieldStart.PreviousSibling ' If a previous run cannot be found then we are forced to use the FieldStart node. If previousNode Is Nothing Then previousNode = fieldStart End If ' Insert a PAGEREF field at the same position as the field. builder.MoveTo(previousNode) ' This will insert a new field with a code like " PAGEREF _SubDocumentEnd0 *\MERGEFORMAT ". Dim newField As Field = builder.InsertField(String.Format(" {0} {1}{2} {3} ", pageRefFieldName, bookmarkPrefix, subDocumentCount, fieldSwitches)) ' The field will be inserted before the referenced node. Move the node before the field instead. previousNode.ParentNode.InsertBefore(previousNode, newField.Start) ' Remove the original NUMPAGES field from the document. RemoveField(fieldStart) End If Next fieldStart Next section
End Sub
‘’’
‘’’ Retrieves the field code from a field.
‘’’
‘’’ The field start of the field which to gather the field code from
‘’’
Private Shared Function GetFieldCode(ByVal fieldStart As FieldStart) As String
Dim builder As New StringBuilder()Dim node As Node = fieldStart Do While node IsNot Nothing AndAlso node.NodeType <> Aspose.Words.NodeType.FieldSeparator AndAlso node.NodeType <> Aspose.Words.NodeType.FieldEnd ' Use text only of Run nodes to avoid duplication. If node.NodeType = Aspose.Words.NodeType.Run Then builder.Append(node.GetText()) End If node = node.NextPreOrder(node.Document) Loop Return builder.ToString()
End Function
‘’’
‘’’ Removes the Field from the document
‘’’
‘’’ The field start node of the field to remove.
Private Shared Sub RemoveField(ByVal fieldStart As FieldStart)
Dim currentNode As Node = fieldStart
Dim isRemoving As Boolean = True
Do While currentNode IsNot Nothing AndAlso isRemoving
If currentNode.NodeType = Aspose.Words.NodeType.FieldEnd Then
isRemoving = False
End IfDim nextNode As Node = currentNode.NextPreOrder(currentNode.Document) currentNode.Remove() currentNode = nextNode Loop
End Sub