Table of Contents

Interface IDocxMailMerge

Namespace
DocToolkit.Extensions.DependencyInjection
Assembly
DocToolkit.Extensions.DependencyInjection.dll

Fills a Word mail-merge template — a document carrying MERGEFIELD instructions — from a set of named values. Registered by AddDocToolkit(IServiceCollection, Action<DocToolkitOptions>?).

public interface IDocxMailMerge

Remarks

Not IDocxEditor's placeholders and not IDocxForm's content controls. The difference is who authored the template: {{placeholder}} is a convention this library invented, a MERGEFIELD is what Word writes from Insert → Merge Field, and a content control is a named region Word protects. A caller has whichever one their document was built with.

Methods

InspectTemplate(byte[])

Reads what docx asks for, without merging anything.

DocxMailMergeTemplate InspectTemplate(byte[] docx)

Parameters

docx byte[]

The template to read.

Returns

DocxMailMergeTemplate

Exceptions

ArgumentNullException

docx is null.

ArgumentException

docx is empty.

DocumentConversionException

It could not be opened or read.

InspectTemplateAsync(Stream, CancellationToken)

Reads what docx asks for, without merging anything.

Task<DocxMailMergeTemplate> InspectTemplateAsync(Stream source, CancellationToken ct = default)

Parameters

source Stream

The template to read. Read to its end; never disposed or sought.

ct CancellationToken

Cancels before the document is read.

Returns

Task<DocxMailMergeTemplate>

Merge(byte[], IReadOnlyDictionary<string, string>)

A copy of docx with every merge field filled.

byte[] Merge(byte[] docx, IReadOnlyDictionary<string, string> values)

Parameters

docx byte[]

The template to fill.

values IReadOnlyDictionary<string, string>

The value for each field, matched case-insensitively.

Returns

byte[]

Remarks

Refuses to produce a document with an unfilled field, naming every one. Measured: an unfilled field survives as a live field and the document reads «Balance» — valid, opening cleanly, and looking finished. Use MergeWithReport(byte[], IReadOnlyDictionary<string, string>) when you want it anyway.

Exceptions

ArgumentNullException

An argument is null.

ArgumentException

docx is empty, or a value is null.

DocumentConversionException

A field received no value, or the document could not be read or written.

MergeAsync(Stream, Stream, IReadOnlyDictionary<string, string>, CancellationToken)

A copy of docx with every merge field filled.

Task MergeAsync(Stream source, Stream destination, IReadOnlyDictionary<string, string> values, CancellationToken ct = default)

Parameters

source Stream

The template to fill. Read to its end; never disposed or sought.

destination Stream

Receives the filled document. Written; never disposed or sought.

values IReadOnlyDictionary<string, string>

The value for each field, matched case-insensitively.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task

MergeBatch(byte[], IEnumerable<IReadOnlyDictionary<string, string>>)

Fills docx once per entry in records, yielding each filled document in order. Strict — refuses the moment a record is incomplete, mid-sequence; everything already yielded before that point is unaffected.

IEnumerable<byte[]> MergeBatch(byte[] docx, IEnumerable<IReadOnlyDictionary<string, string>> records)

Parameters

docx byte[]

The template to fill, once per record.

records IEnumerable<IReadOnlyDictionary<string, string>>

One dictionary of values per output document, matched case-insensitively. An empty sequence yields no documents.

Returns

IEnumerable<byte[]>

Exceptions

ArgumentNullException

docx or records is null, or an individual record in records is null.

ArgumentException

docx is empty, or a record's value is null.

DocumentConversionException

The package could not be read or written, or a record is missing a value for a field the template requires — the message names the record's position (0-based) and the missing field(s).

MergeBatchAsync(byte[], IEnumerable<IReadOnlyDictionary<string, string>>, CancellationToken)

Fills docx once per entry in records, yielding each filled document in order. Strict — refuses the moment a record is incomplete, mid-sequence; everything already yielded before that point is unaffected.

IAsyncEnumerable<byte[]> MergeBatchAsync(byte[] docx, IEnumerable<IReadOnlyDictionary<string, string>> records, CancellationToken ct = default)

Parameters

docx byte[]

The template to fill, once per record.

records IEnumerable<IReadOnlyDictionary<string, string>>

One dictionary of values per output document, matched case-insensitively. An empty sequence yields no documents.

ct CancellationToken

Cancels before the next record's merge runs.

Returns

IAsyncEnumerable<byte[]>

Remarks

Argument validation is not thrown until the caller starts enumerating the result — inherent to how an IAsyncEnumerable<T> iterator method defers its whole body.

MergeBatchWithReport(byte[], IEnumerable<IReadOnlyDictionary<string, string>>)

Fills docx once per entry in records, yielding each record's document together with what happened to every field in it. The lenient half of the pair — always produces a document for every record, complete or not, and never throws for an incomplete one.

IEnumerable<DocxMailMergeBatchItem> MergeBatchWithReport(byte[] docx, IEnumerable<IReadOnlyDictionary<string, string>> records)

Parameters

docx byte[]

The template to fill, once per record.

records IEnumerable<IReadOnlyDictionary<string, string>>

One dictionary of values per output document, matched case-insensitively. An empty sequence yields no items.

Returns

IEnumerable<DocxMailMergeBatchItem>

Exceptions

ArgumentNullException

docx or records is null, or an individual record in records is null.

ArgumentException

docx is empty, or a record's value is null.

DocumentConversionException

The package could not be read or written.

MergeBatchWithReportAsync(byte[], IEnumerable<IReadOnlyDictionary<string, string>>, CancellationToken)

Fills docx once per entry in records, yielding each record's document together with what happened to every field in it. The lenient half of the pair — always produces a document for every record, complete or not, and never throws for an incomplete one.

IAsyncEnumerable<DocxMailMergeBatchItem> MergeBatchWithReportAsync(byte[] docx, IEnumerable<IReadOnlyDictionary<string, string>> records, CancellationToken ct = default)

Parameters

docx byte[]

The template to fill, once per record.

records IEnumerable<IReadOnlyDictionary<string, string>>

One dictionary of values per output document, matched case-insensitively. An empty sequence yields no items.

ct CancellationToken

Cancels before the next record's merge runs.

Returns

IAsyncEnumerable<DocxMailMergeBatchItem>

Remarks

Argument validation is not thrown until the caller starts enumerating the result — the same IAsyncEnumerable<T> deferral MergeBatchAsync(byte[], IEnumerable<IReadOnlyDictionary<string, string>>, CancellationToken) has.

MergeConditional(byte[], IReadOnlyDictionary<string, bool>)

A copy of docx with every conditional block resolved, refusing if the template asks for a condition conditions did not supply.

byte[] MergeConditional(byte[] docx, IReadOnlyDictionary<string, bool> conditions)

Parameters

docx byte[]

The template to resolve.

conditions IReadOnlyDictionary<string, bool>

Whether to include each named block.

Returns

byte[]

Exceptions

ArgumentNullException

An argument is null.

ArgumentException

docx is empty.

DocumentConversionException

A condition the template asks for was not supplied, the marker structure is unbalanced, or the document could not be read or written.

MergeConditionalAsync(Stream, Stream, IReadOnlyDictionary<string, bool>, CancellationToken)

A copy of docx with every conditional block resolved, refusing if the template asks for a condition conditions did not supply.

Task MergeConditionalAsync(Stream source, Stream destination, IReadOnlyDictionary<string, bool> conditions, CancellationToken ct = default)

Parameters

source Stream

The template to resolve. Read to its end; never disposed or sought.

destination Stream

Receives the resolved document. Written; never disposed or sought.

conditions IReadOnlyDictionary<string, bool>

Whether to include each named block.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task

MergeConditionalWithReport(byte[], IReadOnlyDictionary<string, bool>)

A copy of docx with every conditional block resolved, together with which condition names the template asked for that conditions did not supply. Never refuses for a missing name — an unsupplied condition defaults to false.

DocxMailMergeBlockResult MergeConditionalWithReport(byte[] docx, IReadOnlyDictionary<string, bool> conditions)

Parameters

docx byte[]

The template to resolve.

conditions IReadOnlyDictionary<string, bool>

Whether to include each named block.

Returns

DocxMailMergeBlockResult

Exceptions

ArgumentNullException

An argument is null.

ArgumentException

docx is empty.

DocumentConversionException

The marker structure is unbalanced, or the document could not be read or written.

MergeConditionalWithReportAsync(Stream, Stream, IReadOnlyDictionary<string, bool>, CancellationToken)

A copy of docx with every conditional block resolved, together with which condition names the template asked for that conditions did not supply. Never refuses for a missing name — an unsupplied condition defaults to false.

Task<DocxMailMergeBlockReport> MergeConditionalWithReportAsync(Stream source, Stream destination, IReadOnlyDictionary<string, bool> conditions, CancellationToken ct = default)

Parameters

source Stream

The template to resolve. Read to its end; never disposed or sought.

destination Stream

Receives the resolved document. Written; never disposed or sought.

conditions IReadOnlyDictionary<string, bool>

Whether to include each named block.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task<DocxMailMergeBlockReport>

Remarks

Returns the report alone, because the document went to destination.

MergeRepeating(byte[], IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>)

A copy of docx with every repeating block ({{#each Name}}{{/each Name}}) expanded once per entry in its region, refusing if the template asks for a region regions did not supply.

byte[] MergeRepeating(byte[] docx, IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>> regions)

Parameters

docx byte[]

The template to expand.

regions IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>

One sequence of value sets per named repeating region.

Returns

byte[]

Exceptions

ArgumentNullException

An argument is null, or an individual record in it is null.

ArgumentException

docx is empty, or a record's value is null.

DocumentConversionException

A region the template asks for was not supplied, the marker structure is unbalanced, or the document could not be read or written.

MergeRepeatingAsync(Stream, Stream, IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>, CancellationToken)

A copy of docx with every repeating block ({{#each Name}}{{/each Name}}) expanded once per entry in its region, refusing if the template asks for a region regions did not supply.

Task MergeRepeatingAsync(Stream source, Stream destination, IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>> regions, CancellationToken ct = default)

Parameters

source Stream

The template to expand. Read to its end; never disposed or sought.

destination Stream

Receives the expanded document. Written; never disposed or sought.

regions IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>

One sequence of value sets per named repeating region.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task

MergeRepeatingRegions(byte[], IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>)

The nested-region twin of MergeRepeating(byte[], IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>) — each entry may itself carry further nested regions, for a template whose repeating blocks are nested inside one another.

byte[] MergeRepeatingRegions(byte[] docx, IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>> regions)

Parameters

docx byte[]

The template to expand.

regions IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>

One sequence of block rows per named top-level repeating region.

Returns

byte[]

Exceptions

ArgumentNullException

An argument is null, or an individual block row in it is null.

ArgumentException

docx is empty, or a block row's value is null.

DocumentConversionException

A region the template asks for was not supplied at any nesting level, the marker structure is unbalanced, or the document could not be read or written.

MergeRepeatingRegionsAsync(Stream, Stream, IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>, CancellationToken)

The nested-region twin of MergeRepeating(byte[], IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>) — each entry may itself carry further nested regions, for a template whose repeating blocks are nested inside one another.

Task MergeRepeatingRegionsAsync(Stream source, Stream destination, IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>> regions, CancellationToken ct = default)

Parameters

source Stream

The template to expand. Read to its end; never disposed or sought.

destination Stream

Receives the expanded document. Written; never disposed or sought.

regions IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>

One sequence of block rows per named top-level repeating region.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task

MergeRepeatingRegionsWithReport(byte[], IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>)

A copy of docx with every nested repeating region expanded, together with which region names the template asked for — at any nesting level — that regions did not supply. An unsupplied region, at any level, defaults to zero rows rather than refusing.

DocxMailMergeBlockResult MergeRepeatingRegionsWithReport(byte[] docx, IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>> regions)

Parameters

docx byte[]

The template to expand.

regions IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>

One sequence of block rows per named top-level repeating region.

Returns

DocxMailMergeBlockResult

Exceptions

ArgumentNullException

An argument is null, or an individual block row in it is null.

ArgumentException

docx is empty, or a block row's value is null.

DocumentConversionException

The marker structure is unbalanced, or the document could not be read or written.

MergeRepeatingRegionsWithReportAsync(Stream, Stream, IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>, CancellationToken)

A copy of docx with every nested repeating region expanded, together with which region names the template asked for — at any nesting level — that regions did not supply. An unsupplied region, at any level, defaults to zero rows rather than refusing.

Task<DocxMailMergeBlockReport> MergeRepeatingRegionsWithReportAsync(Stream source, Stream destination, IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>> regions, CancellationToken ct = default)

Parameters

source Stream

The template to expand. Read to its end; never disposed or sought.

destination Stream

Receives the expanded document. Written; never disposed or sought.

regions IReadOnlyDictionary<string, IEnumerable<DocxMailMergeBlockData>>

One sequence of block rows per named top-level repeating region.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task<DocxMailMergeBlockReport>

Remarks

Returns the report alone, because the document went to destination.

MergeRepeatingWithReport(byte[], IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>)

A copy of docx with every repeating block expanded, together with which region names the template asked for that regions did not supply. An unsupplied region defaults to zero rows rather than refusing.

DocxMailMergeBlockResult MergeRepeatingWithReport(byte[] docx, IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>> regions)

Parameters

docx byte[]

The template to expand.

regions IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>

One sequence of value sets per named repeating region.

Returns

DocxMailMergeBlockResult

Exceptions

ArgumentNullException

An argument is null, or an individual record in it is null.

ArgumentException

docx is empty, or a record's value is null.

DocumentConversionException

The marker structure is unbalanced, or the document could not be read or written.

MergeRepeatingWithReportAsync(Stream, Stream, IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>, CancellationToken)

A copy of docx with every repeating block expanded, together with which region names the template asked for that regions did not supply. An unsupplied region defaults to zero rows rather than refusing.

Task<DocxMailMergeBlockReport> MergeRepeatingWithReportAsync(Stream source, Stream destination, IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>> regions, CancellationToken ct = default)

Parameters

source Stream

The template to expand. Read to its end; never disposed or sought.

destination Stream

Receives the expanded document. Written; never disposed or sought.

regions IReadOnlyDictionary<string, IEnumerable<IReadOnlyDictionary<string, string>>>

One sequence of value sets per named repeating region.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task<DocxMailMergeBlockReport>

Remarks

Returns the report alone, because the document went to destination.

MergeTableRowGroups(byte[], int, int, int, IEnumerable<DocxMailMergeTableRowGroup>)

A copy of docx with a group/header row and its detail row template, both in the table at tableIndex, repeated once per group in groups. Index-based, like MergeTableRows(byte[], int, int, IEnumerable<IReadOnlyDictionary<string, string>>); no strict/lenient split.

byte[] MergeTableRowGroups(byte[] docx, int tableIndex, int groupTemplateRowIndex, int detailTemplateRowIndex, IEnumerable<DocxMailMergeTableRowGroup> groups)

Parameters

docx byte[]

The template to expand.

tableIndex int

Zero-based index of the table, in document order.

groupTemplateRowIndex int

Zero-based row index of the group/header row template.

detailTemplateRowIndex int

Zero-based row index of the detail row template.

groups IEnumerable<DocxMailMergeTableRowGroup>

One group/header value set, with its detail rows, per generated group.

Returns

byte[]

Exceptions

ArgumentNullException

An argument is null, or an individual group or detail row in it is null.

ArgumentException

docx is empty, or a group or detail row's value is null.

DocumentConversionException

tableIndex, groupTemplateRowIndex or detailTemplateRowIndex is out of range, or the document could not be read or written.

MergeTableRowGroupsAsync(Stream, Stream, int, int, int, IEnumerable<DocxMailMergeTableRowGroup>, CancellationToken)

A copy of docx with a group/header row and its detail row template, both in the table at tableIndex, repeated once per group in groups. Index-based, like MergeTableRows(byte[], int, int, IEnumerable<IReadOnlyDictionary<string, string>>); no strict/lenient split.

Task MergeTableRowGroupsAsync(Stream source, Stream destination, int tableIndex, int groupTemplateRowIndex, int detailTemplateRowIndex, IEnumerable<DocxMailMergeTableRowGroup> groups, CancellationToken ct = default)

Parameters

source Stream

The template to expand. Read to its end; never disposed or sought.

destination Stream

Receives the expanded document. Written; never disposed or sought.

tableIndex int

Zero-based index of the table, in document order.

groupTemplateRowIndex int

Zero-based row index of the group/header row template.

detailTemplateRowIndex int

Zero-based row index of the detail row template.

groups IEnumerable<DocxMailMergeTableRowGroup>

One group/header value set, with its detail rows, per generated group.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task

MergeTableRows(byte[], int, int, IEnumerable<IReadOnlyDictionary<string, string>>)

A copy of docx with the row at templateRowIndex in the table at tableIndex repeated once per entry in rows. Index-based rather than marker-based — no strict/lenient split, since there is no name that could go unsupplied.

byte[] MergeTableRows(byte[] docx, int tableIndex, int templateRowIndex, IEnumerable<IReadOnlyDictionary<string, string>> rows)

Parameters

docx byte[]

The template to expand.

tableIndex int

Zero-based index of the table, in document order.

templateRowIndex int

Zero-based row index within that table to clone and bind.

rows IEnumerable<IReadOnlyDictionary<string, string>>

One value set per generated row.

Returns

byte[]

Exceptions

ArgumentNullException

An argument is null, or an individual row in it is null.

ArgumentException

docx is empty, or a row's value is null.

DocumentConversionException

tableIndex or templateRowIndex is out of range, or the document could not be read or written.

MergeTableRowsAsync(Stream, Stream, int, int, IEnumerable<IReadOnlyDictionary<string, string>>, CancellationToken)

A copy of docx with the row at templateRowIndex in the table at tableIndex repeated once per entry in rows. Index-based rather than marker-based — no strict/lenient split, since there is no name that could go unsupplied.

Task MergeTableRowsAsync(Stream source, Stream destination, int tableIndex, int templateRowIndex, IEnumerable<IReadOnlyDictionary<string, string>> rows, CancellationToken ct = default)

Parameters

source Stream

The template to expand. Read to its end; never disposed or sought.

destination Stream

Receives the expanded document. Written; never disposed or sought.

tableIndex int

Zero-based index of the table, in document order.

templateRowIndex int

Zero-based row index within that table to clone and bind.

rows IEnumerable<IReadOnlyDictionary<string, string>>

One value set per generated row.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task

MergeWithReport(byte[], IReadOnlyDictionary<string, string>)

A copy of docx with every merge field filled, together with what happened to each one. Always produces a document, complete or not.

DocxMailMergeResult MergeWithReport(byte[] docx, IReadOnlyDictionary<string, string> values)

Parameters

docx byte[]

The template to fill.

values IReadOnlyDictionary<string, string>

The value for each field, matched case-insensitively.

Returns

DocxMailMergeResult

Exceptions

ArgumentNullException

An argument is null.

ArgumentException

docx is empty, or a value is null.

DocumentConversionException

It could not be read or written.

MergeWithReportAsync(Stream, Stream, IReadOnlyDictionary<string, string>, CancellationToken)

A copy of docx with every merge field filled, together with what happened to each one. Always produces a document, complete or not.

Task<DocxMailMergeReport> MergeWithReportAsync(Stream source, Stream destination, IReadOnlyDictionary<string, string> values, CancellationToken ct = default)

Parameters

source Stream

The template to fill. Read to its end; never disposed or sought.

destination Stream

Receives the filled document. Written; never disposed or sought.

values IReadOnlyDictionary<string, string>

The value for each field, matched case-insensitively.

ct CancellationToken

Cancels before the document is read, and while it is written.

Returns

Task<DocxMailMergeReport>

Remarks

Returns the report alone, because the document went to destination.