Inconsistent behaviour manipulating HeaderFooter

Hello

We are migrating our PDF’s to the new Aspose schema (from version 11 to 25.10.0) and one of the tasks we need to do programatically, is to display headers and footers in subsequent pages because when the content grows, it might create more pages.

We have defined 2 pages in our XML file, and we want to grab the header and footer from the 2nd page and show it in subsequent pages but we are seeing inconsistent behaviour. Sometimes we are able to replace the 1st page header in pages 2…n with the one from the 2nd page but we we do the same transformation some time later it doesn’t happen.

Here’s our code right now>

public byte[] GenerateFromXml(XmlDocument xmlContent)
{
    byte[] xmlBytes = Encoding.UTF8.GetBytes(xmlContent.OuterXml);

    using (var stream = new MemoryStream(xmlBytes))
    {
        try
        {
            this._pdf.BindXml(stream, null);
        }
        catch (Aspose.Pdf.InvalidValueFormatException ex)
        {
            Console.WriteLine("Bad attribute: " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

    int pageCount = _pdf.Pages.Count;
    PageInfo lastPageInfo = _pdf.Pages[pageCount].PageInfo;
    lastPageInfo.Margin = new MarginInfo(55, 100, 55, 60);
    HeaderFooter lastPageHeader = _pdf.Pages[pageCount].Header;
    HeaderFooter lastPageFooter = _pdf.Pages[pageCount].Footer;

    foreach (Page page in _pdf.Pages)
    {
        if (page.Number > 1)
        {
            page.Header = lastPageHeader;
            page.PageInfo = lastPageInfo;
        }

        foreach (var para in page.Paragraphs)
        {
            var table = para as Table;

            if (table == null)
                continue;

            foreach (Row row in table.Rows)
            {
                if(row.MinRowHeight <= 0)
                {
                    foreach (Cell cell in row.Cells)
                    {
                        cell.VerticalAlignment = VerticalAlignment.Top;
                    }
                }
            }
        }
    }

    return AsStream();
}

And the AsStream>

private byte[] AsStream()
{
    using (var ms = new MemoryStream())
    {
        _pdf.Save(ms);

        var result = ms.ToArray();
        ms.Flush();
        ms.Close();

        return result;
    }
}

The _pdf is of type Document.

What’s the mechanism behind BindXML? Why are we able to achieve headers replacement sometimes but not always?

@FabioM

BindXml only parses the XML representation of a PDF and builds the Document object model from it.
During this process each page gets its own HeaderFooter instance that is stored inside the page’s Header/Footer properties. The objects are not shared between pages – they are created per‑page when the XML is read.

In your code you take the HeaderFooter instance from the last page:

HeaderFooter lastPageHeader = _pdf.Pages[pageCount].Header;
HeaderFooter lastPageFooter = _pdf.Pages[pageCount].Footer;

and then assign the same instance to every other page:

page.Header = lastPageHeader;
page.Footer = lastPageFooter;

Because the same object is now referenced by multiple pages, any later modification that the PDF engine performs (e.g., layout re‑flow when content is added, page splitting, or internal cleanup after Save) can overwrite the header/footer of some pages while leaving others untouched. This is why the behaviour appears intermittent.

Recommended fix

Create a clone of the header/footer for each target page instead of re‑using the original instance:

HeaderFooter lastPageHeader = _pdf.Pages[pageCount].Header;
HeaderFooter lastPageFooter = _pdf.Pages[pageCount].Footer;

foreach (Page page in _pdf.Pages)
{
    if (page.Number > 1)
    {
        // deep clone – copies all elements (text, images, etc.)
        page.Header = (HeaderFooter)lastPageHeader.Clone(true);
        page.Footer = (HeaderFooter)lastPageFooter.Clone(true);

        // apply the same PageInfo if required
        page.PageInfo = (PageInfo)lastPageInfo.Clone();
    }
}
  • Clone(true) performs a deep copy, ensuring each page gets its own independent header/footer object.
  • Cloning PageInfo (or creating a new PageInfo and copying the needed margins) prevents later layout changes from affecting the original page’s settings.

Additional checks

  1. Version – make sure you are using the latest 25.x release; a few header/footer handling bugs were fixed in recent updates.
  2. XML schema – verify that the source XML defines the header/footer only on the second page; any stray <Header>/<Footer> elements on other pages will be loaded by BindXml and may override your manual changes.
  3. Content changes after binding – if you add or remove paragraphs/tables after the foreach loop, new pages can be created. In that case you need to repeat the header/footer assignment for the newly created pages.

If the problem persists after applying the clone approach, please provide:

  • A minimal XML sample that reproduces the issue.
  • The exact Aspose.Pdf for .NET version you are using.
  • Any stack trace or warning messages that appear during Save.

With that information we can log a detailed defect if required.

@Professionalize.Discourse

Thank you for your help.

It doesn’t seem we have an overload for the Clone method, can only call Clone() on the HeaderFooter object but in any case the pdf isn’t being generated with the last page header and footers in subsequent pages.

1- Here’s a minimal XML:

<?xml version="1.0" encoding="utf-8"?>
<Document xmlns="Aspose.Pdf" xmlns:fo="http://www.w3.org/1999/XSL/Format" xsi:schemaLocation="Aspose.Pdf schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Page>
		<PageInfo>
			<Margin Left="50" Right="50" Top="56" Bottom="56"></Margin>
		</PageInfo>
		<Header>
			<Margin Left="50" Right="50" Top="20" Bottom="10"></Margin>
			<Table ColumnWidths="150 450">
				<DefaultCellPadding Top="20" Right="0" Bottom="20" Left="0"></DefaultCellPadding>
				<Row>
					<Cell>
						<Image File="someLogo.png" ImageScale="0.26" HorizontalAlignment="0" />
					</Cell>
					<Cell Alignment="3">
						<TextFragment>
							<TextSegment>Bayer. Landesamt für Steuern - Steuerabt.</TextSegment>
							<TextState Font="Arial" FontSize="16" />
						</TextFragment>
						<Margin Bottom="20" Right="0" Left="0" Top="0" />
					</Cell>
				</Row>
			</Table>
		</Header>
<Table ColumnWidths="100 300 100">
	<Margin Bottom="10" Top="10"></Margin>
	<Row>
		<DefaultCellTextState FontSize="9"></DefaultCellTextState>
		<Cell>
			<TextFragment>
				<TextSegment>Delivery terms:</TextSegment>
			</TextFragment>
		</Cell>
		<Cell>
			<TextFragment>
				<TextSegment>-</TextSegment>
			</TextFragment>
		</Cell>
		<Cell></Cell>
	</Row>
	<Row>
		<DefaultCellTextState FontSize="9"></DefaultCellTextState>
		<Cell>
			<TextFragment>
				<TextSegment>Payment terms:</TextSegment>
			</TextFragment>
		</Cell>
		<Cell>
			<TextFragment>
				<TextSegment>21 Tage 2% Skonto, 30 Tage netto</TextSegment>
			</TextFragment>
		</Cell>
		<Cell Alignment="3">
			<TextFragment>
				<TextSegment>Currency: EUR</TextSegment>
			</TextFragment>
		</Cell>
	</Row>
</Table>
	</Page>
	<Page>
		<!--PageInfo works the same as a page canvas-->
		<PageInfo>
			<Margin Left="55" Right="55" Top="60" Bottom="100"></Margin>
		</PageInfo>
		<Header>
			<Margin Left="40" Right="40" Top="20" Bottom="10"></Margin>
			<Table ColumnWidths="150 450">
				<DefaultCellPadding Top="20" Right="0" Bottom="20" Left="0"></DefaultCellPadding>
				<Row>
					<Cell>
						<Image File="someLogo.png" ImageScale="0.26" HorizontalAlignment="0" />
					</Cell>
					<Cell Alignment="3">
						<TextFragment>
							<TextSegment>Bayer. Landesamt für Steuern - Steuerabt. on Page 2 and next</TextSegment>
							<TextState Font="Arial" FontSize="16" />
						</TextFragment>
						<Margin Bottom="20" Right="0" Left="0" Top="0" />
					</Cell>
				</Row>
			</Table>
		</Header>
		<Footer>
			<TextFragment>
				<TextSegment>80333 München 2</TextSegment>
				<TextState Font="Arial" FontSize="9" />
			</TextFragment>
		</Footer>
	</Page>
</Document>

2- We are using Aspose 25.10.0
3- No stack trace or warning messages appear.

@FabioM

Zusammenfassung des Problems
Sie lesen ein PDF‑Dokument aus XML (BindXml) und übernehmen anschließend das Header‑/Footer‑Objekt der letzten Seite für alle vorherigen Seiten:

HeaderFooter lastPageHeader = _pdf.Pages[pageCount].Header;
HeaderFooter lastPageFooter = _pdf.Pages[pageCount].Footer;

foreach (Page page in _pdf.Pages)
{
    if (page.Number > 1)
    {
        page.Header = lastPageHeader;   // ← gleiche Instanz
        page.Footer = lastPageFooter;
    }
}

Da dieselbe HeaderFooter‑Instanz mehreren Seiten zugewiesen wird, greift der PDF‑Renderer intern bei Layout‑ oder Speicher‑Operationen auf das Objekt zu und überschreibt es teilweise. Deshalb erscheint das Header‑/Footer‑Verhalten nur sporadisch [1][2].


1. Warum Clone() allein nicht ausreicht

  • HeaderFooter.Clone() ohne Parameter erzeugt keine tiefe Kopie – es wird nur ein flacher Klon erstellt, der intern noch Referenzen auf dieselben Unterobjekte (z. B. Paragraphs, Images) enthält. Beim späteren Layout‑Durchlauf können diese geteilten Objekte von einer Seite verändert werden und damit andere Seiten beeinflussen [1][2].

  • In Aspose.PDF .NET gibt es die überladene Methode HeaderFooter.Clone(bool deepCopy). Wird true übergeben, erfolgt eine tiefe Kopie aller enthaltenen Elemente [1][2].


2. Korrekte Vorgehensweise (Deep‑Clone pro Zielseite)

// Header und Footer der letzten Seite holen
HeaderFooter lastPageHeader = _pdf.Pages[pageCount].Header;
HeaderFooter lastPageFooter = _pdf.Pages[pageCount].Footer;

// Optional: PageInfo ebenfalls klonen, falls Sie die Margins übernehmen wollen
PageInfo lastPageInfo = _pdf.Pages[pageCount].PageInfo;
PageInfo clonedInfo = (PageInfo)lastPageInfo.Clone();   // tiefer Klon

foreach (Page page in _pdf.Pages)
{
    if (page.Number > 1)               // alle Seiten außer der ersten
    {
        // tiefe Kopie erzeugen – jede Seite bekommt ihr eigenes Objekt
        page.Header   = (HeaderFooter)lastPageHeader.Clone(true);
        page.Footer   = (HeaderFooter)lastPageFooter.Clone(true);
        page.PageInfo = clonedInfo;    // falls nötig
    }
}

Clone(true) dupliziert alle Paragraphen, Bilder, Tabellen usw.. Jede Seite arbeitet anschließend mit einer unabhängigen Header/Footer‑Instanz, sodass das Layout‑Engine‑Verhalten konsistent bleibt [1][2].


3. Zusätzliche Einstellungen prüfen

  • Anzeige‑Steuerung: Die Eigenschaften IsFirstPageOnly, IsSubsequentPagesOnly und IsLastPageOnly bestimmen, auf welchen Seiten ein Header/Footer sichtbar ist. Standardmäßig sind sie false. Stellen Sie sicher, dass Sie sie nicht versehentlich auf true gesetzt haben [5].
page.Header.IsFirstPageOnly = false;
page.Header.IsSubsequentPagesOnly = false;
page.Header.IsLastPageOnly = false;
  • Version: Die Clone(bool)‑Überladung ist bereits ab Aspose.PDF .NET 25.10.0 verfügbar. Sollte die Methode in Ihrer Umgebung nicht sichtbar sein, prüfen Sie, ob die korrekte Aspose.Pdf‑Assembly referenziert ist und führen Sie ggf. einen Clean‑Build durch. Ein Update auf die aktuelle 25.x‑Patch‑Version kann ebenfalls helfen, da einige Header/Footer‑Bugs in neueren Builds behoben wurden [1][2].

4. Vorgehen, wenn das Problem weiterhin besteht

  1. Reproduktions‑Sample: Erstellen Sie ein minimales XML‑Dokument (wie in Ihrer Frage) und führen Sie den obigen Code aus.
  2. Ergebnis prüfen: Alle Seiten ab Seite 2 sollten exakt den Header und Footer der letzten Seite zeigen.
  3. Falls nicht:
    • Vergewissern Sie sich, dass nach dem Klon‑Schritt keine weiteren Änderungen an page.Header/page.Footer vorgenommen werden (z. B. weitere Add‑Aufrufe).
    • Geben Sie die exakte Aspose.Pdf‑Version (inkl. Patch‑Nummer) und ggf. einen Stack‑Trace aus, falls beim Save eine Ausnahme auftritt.

Sollte das Verhalten trotz tiefem Klonen weiterhin inkonsistent sein, handelt es sich vermutlich um einen Produkt‑Defekt. In diesem Fall kann das Problem intern geloggt und an das Entwicklungsteam weitergeleitet werden.


Kurzfassung

  • Verwenden Sie HeaderFooter.Clone(true) (tiefe Kopie) statt des parameterlosen Clone().
  • Weisen Sie jeder Zielseite eine eigene geklonte Instanz zu.
  • Prüfen Sie die Flags IsFirstPageOnly, IsSubsequentPagesOnly und IsLastPageOnly.
  • Bei weiterem Fehlverhalten ein Minimal‑Reproduktions‑Sample bereitstellen, damit ein möglicher Defekt gemeldet werden kann.

@FabioM

We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): PDFNET-61430

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.