Table of Contents

Class DocxForm

Namespace
DocToolkit
Assembly
DocToolkit.Docx.dll

Reads, checks and fills the content controls a Word document carries — the format's own answer to a fill-in form.

public static class DocxForm
Inheritance
DocxForm
Inherited Members

Remarks

This library now has three template models, and a caller has whichever one their document was authored with. They are not interchangeable and none replaces the others:

modelmarker · who writes it
DocxEditor {{placeholder}} — plain text, typed by anyone. A convention this library invented, and breakable by editing inside the token.
DocxMailMerge MERGEFIELD — a real Word field, from Insert → Merge Field.
this class a content control — a named region Word itself protects, which is what makes it sturdier than a placeholder.

Validate(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey) checks keys and, for a typed control, values. A drop-down value outside its list, a non-date for a date picker and a non-boolean for a check box are each reported under their own kind. A plain text control validates anything, because there is no constraint to check it against.

Fill(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey) is lenient about a MISSING value, where Merge(byte[], IReadOnlyDictionary<string, string>) refuses. Two measured differences justify that: a control given no value keeps its own existing text rather than showing an injected marker, and unlike mail merge this class ships a Validate a caller can run first.

It is NOT lenient about a value that does not fit a typed control, and the three typed kinds do not agree with each other. Measured: a drop-down value outside its list throws, while a non-date for a date picker and a non-boolean for a check box are silently skipped and the control keeps its old content. That asymmetry is the library beneath, not a choice made here — which is the strongest reason to run Validate first, since it reports all three the same way, before anything is written.

Only the document BODY is read or written. A content control in a header or a footer is invisible to every method here: it is not in Inspect(byte[], DocxFormKey)'s report, a value aimed at it is reported as UnusedValue — which reads as though the caller invented the name — and Fill leaves it untouched. Measured. DocxMailMerge does reach headers, so the two template APIs genuinely differ here; if your form lives in a header, that is the one to use.

Images are supplied as bytes and never as a path — see DocxFormValue.

Methods

Fill(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey)

A copy of docx with each named control set to its value.

public static byte[] Fill(byte[] docx, IReadOnlyDictionary<string, DocxFormValue> values, DocxFormKey key = DocxFormKey.TagThenAlias)

Parameters

docx byte[]

The document to fill.

values IReadOnlyDictionary<string, DocxFormValue>

The value for each control.

key DocxFormKey

Which name identifies a control.

Returns

byte[]

Remarks

Lenient. A control with no entry in values is left exactly as it was — measured: it keeps its own text rather than showing a marker, so a partial fill is a supported workflow. Call Validate(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey) first if you need to know what will be skipped.

This returns bytes rather than a count of what it wrote. The count answers "did my data match this template?", which is Validate's question and is better asked before a document exists than inferred from one.

Exceptions

ArgumentNullException

docx or values is null.

ArgumentException

docx is empty, or a value is null.

DocumentConversionException

The document could not be read or written, or a value did not fit a typed control in a way the library beneath refuses — measured: a drop-down value outside its list throws here, while a bad date or boolean is skipped silently. Run Validate(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey) first to see all three before writing.

FillAsync(Stream, Stream, IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey, CancellationToken)

Writes a copy of the document in source to destination with each named control set to its value. source is read to its end and destination is written; neither is disposed, closed nor sought.

public static Task FillAsync(Stream source, Stream destination, IReadOnlyDictionary<string, DocxFormValue> values, DocxFormKey key = DocxFormKey.TagThenAlias, CancellationToken ct = default)

Parameters

source Stream

The document to fill.

destination Stream

Receives the filled document.

values IReadOnlyDictionary<string, DocxFormValue>

The value for each control.

key DocxFormKey

Which name identifies a control.

ct CancellationToken

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

Returns

Task

Remarks

Lenient. A control with no entry in values is left exactly as it was — measured: it keeps its own text rather than showing a marker, so a partial fill is a supported workflow. Call Validate(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey) first if you need to know what will be skipped.

This returns bytes rather than a count of what it wrote. The count answers "did my data match this template?", which is Validate's question and is better asked before a document exists than inferred from one.

Exceptions

ArgumentNullException

A stream or values is null.

ArgumentException

A stream is unusable, source held no bytes, or a value is null.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The document could not be read or written.

InvalidOperationException

The fill would change a content control the document locks against editing (A119). Nothing is written, and the document passed in is untouched. Before 0.54.0 this succeeded and left the lock in place, producing a file that declared the control protected while its content had been replaced.

Inspect(byte[], DocxFormKey)

Reads the content controls in docx's body, and what they hold.

public static DocxFormReport Inspect(byte[] docx, DocxFormKey key = DocxFormKey.TagThenAlias)

Parameters

docx byte[]

The document to read.

key DocxFormKey

Which name identifies a control.

Returns

DocxFormReport

Remarks

Not every control in the document — see Fields for the three reasons one can be absent. A document with no content controls reports none rather than failing, which is how a caller catches having passed the wrong document, since filling one succeeds and changes nothing.

Exceptions

ArgumentNullException

docx is null.

ArgumentException

docx is empty.

DocumentConversionException

The document could not be opened or read.

InspectAsync(Stream, DocxFormKey, CancellationToken)

Reads every content control in the document in source. source is read to its end and is neither disposed, closed nor sought.

public static Task<DocxFormReport> InspectAsync(Stream source, DocxFormKey key = DocxFormKey.TagThenAlias, CancellationToken ct = default)

Parameters

source Stream

The document to read.

key DocxFormKey

Which name identifies a control.

ct CancellationToken

Cancels before the document is read.

Returns

Task<DocxFormReport>

Remarks

Not every control in the document — see Fields for the three reasons one can be absent. A document with no content controls reports none rather than failing, which is how a caller catches having passed the wrong document, since filling one succeeds and changes nothing.

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The document could not be opened or read.

Validate(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey)

Checks values against the controls in docx, without writing anything.

public static DocxFormValidation Validate(byte[] docx, IReadOnlyDictionary<string, DocxFormValue> values, DocxFormKey key = DocxFormKey.TagThenAlias)

Parameters

docx byte[]

The document to check against.

values IReadOnlyDictionary<string, DocxFormValue>

The values to check.

key DocxFormKey

Which name identifies a control.

Returns

DocxFormValidation

Remarks

Run this before Fill(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey), which will not tell you what it skipped.

It is not a complete guarantee that Fill will succeed. Measured: image bytes that are not a readable image validate clean and then throw from Fill, because nothing here decodes them. A clean result means no key or typed-value problem was found.

Every issue is reported and IsValid means "none of any kind". Filter Issues by Kind if you do not care about one of them.

Exceptions

ArgumentNullException

docx or values is null.

ArgumentException

docx is empty, or a value is null.

DocumentConversionException

The document could not be opened or read.

ValidateAsync(Stream, IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey, CancellationToken)

Checks values against the document in source. source is read to its end and is neither disposed, closed nor sought.

public static Task<DocxFormValidation> ValidateAsync(Stream source, IReadOnlyDictionary<string, DocxFormValue> values, DocxFormKey key = DocxFormKey.TagThenAlias, CancellationToken ct = default)

Parameters

source Stream

The document to check against.

values IReadOnlyDictionary<string, DocxFormValue>

The values to check.

key DocxFormKey

Which name identifies a control.

ct CancellationToken

Cancels before the document is read.

Returns

Task<DocxFormValidation>

Remarks

Run this before Fill(byte[], IReadOnlyDictionary<string, DocxFormValue>, DocxFormKey), which will not tell you what it skipped.

It is not a complete guarantee that Fill will succeed. Measured: image bytes that are not a readable image validate clean and then throw from Fill, because nothing here decodes them. A clean result means no key or typed-value problem was found.

Every issue is reported and IsValid means "none of any kind". Filter Issues by Kind if you do not care about one of them.

Exceptions

ArgumentNullException

source or values is null.

ArgumentException

A stream is unusable, source held no bytes, or a value is null.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The document could not be opened or read.