Table of Contents

Class WorkbookEditor

Namespace
DocToolkit
Assembly
DocToolkit.Xlsx.dll

Creates, reads and edits Excel (.xlsx) workbooks. Legacy .xls is not supported.

public static class WorkbookEditor
Inheritance
WorkbookEditor
Inherited Members

Methods

AddChart(byte[], string, string, ChartType, ChartData, string, int, int)

Adds a chart to sheetName, anchored at cellRef, and returns the updated workbook.

public static byte[] AddChart(byte[] xlsx, string sheetName, string cellRef, ChartType type, ChartData data, string title = "", int widthPixels = 640, int heightPixels = 360)

Parameters

xlsx byte[]

The workbook to add the chart to. It is not modified.

sheetName string

The sheet to add the chart to.

cellRef string

An A1-style cell reference for the chart's top-left corner, e.g. "B2".

type ChartType

The chart's shape.

data ChartData

The chart's categories and value series.

title string

The chart's title. Empty for no title.

widthPixels int

The chart's width, in pixels.

heightPixels int

The chart's height, in pixels.

Returns

byte[]

Exceptions

ArgumentNullException

xlsx, data or another required argument is null.

ArgumentException

xlsx is empty, or sheetName/cellRef is blank.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

AddChartAsync(Stream, string, string, ChartType, ChartData, Stream, string, int, int, CancellationToken)

Reads a workbook from source, adds a chart, and writes the result to destination — see AddChart(byte[], string, string, ChartType, ChartData, string, int, int) for the parameters.

source is read to its end and destination is written; neither is disposed, closed or sought, and neither has to be seekable.

public static Task AddChartAsync(Stream source, string sheetName, string cellRef, ChartType type, ChartData data, Stream destination, string title = "", int widthPixels = 640, int heightPixels = 360, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

sheetName string

The sheet to add the chart to.

cellRef string

An A1-style cell reference for the chart's top-left corner, e.g. "B2".

type ChartType

The chart's shape.

data ChartData

The chart's categories and value series.

destination Stream

The stream the updated workbook is written to.

title string

The chart's title. Empty for no title.

widthPixels int

The chart's width, in pixels.

heightPixels int

The chart's height, in pixels.

ct CancellationToken

Cancels the read, the edit and the write.

Returns

Task

Exceptions

ArgumentNullException

source, destination or data is null.

ArgumentException

source is not readable or held no bytes, a name is blank, or destination is not writable.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

AddChartAsync(string, string, string, string, ChartType, ChartData, string, int, int, CancellationToken)

Reads a workbook from inputPath, adds a chart, and writes the result to outputPath — see AddChart(byte[], string, string, ChartType, ChartData, string, int, int) for the parameters. The two paths may be the same file: the updated bytes are computed in full before outputPath is opened.

public static Task AddChartAsync(string inputPath, string outputPath, string sheetName, string cellRef, ChartType type, ChartData data, string title = "", int widthPixels = 640, int heightPixels = 360, CancellationToken ct = default)

Parameters

inputPath string

The workbook to read.

outputPath string

Where to write the result. Overwritten if it exists.

sheetName string

The sheet to add the chart to.

cellRef string

An A1-style cell reference for the chart's top-left corner, e.g. "B2".

type ChartType

The chart's shape.

data ChartData

The chart's categories and value series.

title string

The chart's title. Empty for no title.

widthPixels int

The chart's width, in pixels.

heightPixels int

The chart's height, in pixels.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Exceptions

ArgumentNullException

A path, a name or data is null.

ArgumentException

A path or a name is blank, or the file at inputPath is empty.

FileNotFoundException

inputPath does not exist.

DirectoryNotFoundException

inputPath's or outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

AddDefinedName(byte[], string, string, string)

Adds a workbook-scoped defined name pointing at range on sheetName, and returns the updated workbook.

public static byte[] AddDefinedName(byte[] xlsx, string name, string sheetName, string range)

Parameters

xlsx byte[]

The workbook to add the defined name to. It is not modified.

name string

The defined name.

sheetName string

The sheet range is on.

range string

The cells the name refers to, such as A1:B2.

Returns

byte[]

Remarks

sheetName is always single-quoted in the reference this writes (e.g. 'Sales'!A1:B2), whether or not it needs to be. Measured directly: a sheet name containing a space and left unquoted does not raise an error at write time — the defined name simply is not present when the file is reopened, with nothing telling the caller why. Quoting a name with no space is harmless, so this is not a conditional worth the risk of getting the "needs quoting" rule wrong.

Exceptions

ArgumentNullException

Any argument is null.

ArgumentException

xlsx is empty, a name argument is blank, or range names a sheet.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or name is already in use.

AddDefinedNameAsync(Stream, string, string, string, Stream, CancellationToken)

Reads a workbook from source, adds a defined name, and writes the result to destination — see AddDefinedName(byte[], string, string, string) for the parameters.

source is read to its end and destination is written; neither is disposed, closed or sought, and neither has to be seekable.

public static Task AddDefinedNameAsync(Stream source, string name, string sheetName, string range, Stream destination, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

name string

The defined name.

sheetName string

The sheet range is on.

range string

The cells the name refers to, such as A1:B2.

destination Stream

The stream the updated workbook is written to.

ct CancellationToken

Cancels the read, the edit and the write.

Returns

Task

Exceptions

ArgumentNullException

Any argument is null.

ArgumentException

source is not readable or held no bytes, a name argument is blank, range names a sheet, or destination is not writable.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or name is already in use.

AddDefinedNameAsync(string, string, string, string, string, CancellationToken)

Reads a workbook from inputPath, adds a defined name, and writes the result to outputPath — see AddDefinedName(byte[], string, string, string) for the parameters. The two paths may be the same file: the updated bytes are computed in full before outputPath is opened.

public static Task AddDefinedNameAsync(string inputPath, string outputPath, string name, string sheetName, string range, CancellationToken ct = default)

Parameters

inputPath string

The workbook to read.

outputPath string

Where to write the result. Overwritten if it exists.

name string

The defined name.

sheetName string

The sheet range is on.

range string

The cells the name refers to, such as A1:B2.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Exceptions

ArgumentNullException

A path or a name argument is null.

ArgumentException

A path or a name argument is blank, range names a sheet, or the file at inputPath is empty.

FileNotFoundException

inputPath does not exist.

DirectoryNotFoundException

inputPath's or outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or name is already in use.

AddImage(byte[], string, string, byte[], int?, int?)

Inserts image into sheetName, anchored at cellRef, and returns the updated workbook.

public static byte[] AddImage(byte[] xlsx, string sheetName, string cellRef, byte[] image, int? widthPixels = null, int? heightPixels = null)

Parameters

xlsx byte[]

The workbook to add the image to. It is not modified.

sheetName string

The sheet to add the image to.

cellRef string

An A1-style cell reference for the image's top-left corner, e.g. "B2".

image byte[]

The image bytes. PNG and JPEG only, decided by magic bytes.

widthPixels int?

The image's width, in pixels. null uses the image's own intrinsic width, scaled to match heightPixels if that is given.

heightPixels int?

The image's height, in pixels. null uses the image's own intrinsic height, scaled to match widthPixels if that is given.

Returns

byte[]

Exceptions

ArgumentNullException

xlsx, image or another required argument is null.

ArgumentException

xlsx or image is empty, or sheetName/cellRef is blank.

ArgumentOutOfRangeException

A supplied size is zero or negative.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, the reference is not valid, or the image is neither PNG nor JPEG.

AddImageAsync(Stream, string, string, byte[], Stream, int?, int?, CancellationToken)

Reads a workbook from source, adds an image, and writes the result to destination — see AddImage(byte[], string, string, byte[], int?, int?) for the parameters.

source is read to its end and destination is written; neither is disposed, closed or sought, and neither has to be seekable.

public static Task AddImageAsync(Stream source, string sheetName, string cellRef, byte[] image, Stream destination, int? widthPixels = null, int? heightPixels = null, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

sheetName string

The sheet to add the image to.

cellRef string

An A1-style cell reference for the image's top-left corner, e.g. "B2".

image byte[]

The image bytes. PNG and JPEG only, decided by magic bytes.

destination Stream

The stream the updated workbook is written to.

widthPixels int?

The image's width, in pixels. See AddImage(byte[], string, string, byte[], int?, int?).

heightPixels int?

The image's height, in pixels. See AddImage(byte[], string, string, byte[], int?, int?).

ct CancellationToken

Cancels the read, the edit and the write.

Returns

Task

Exceptions

ArgumentNullException

source, destination or image is null.

ArgumentException

source is not readable or held no bytes, image is empty, a name is blank, or destination is not writable.

ArgumentOutOfRangeException

A supplied size is zero or negative.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, the reference is not valid, or the image is neither PNG nor JPEG.

AddImageAsync(string, string, string, string, byte[], int?, int?, CancellationToken)

Reads a workbook from inputPath, adds an image, and writes the result to outputPath — see AddImage(byte[], string, string, byte[], int?, int?) for the parameters. The two paths may be the same file: the updated bytes are computed in full before outputPath is opened.

public static Task AddImageAsync(string inputPath, string outputPath, string sheetName, string cellRef, byte[] image, int? widthPixels = null, int? heightPixels = null, CancellationToken ct = default)

Parameters

inputPath string

The workbook to read.

outputPath string

Where to write the result. Overwritten if it exists.

sheetName string

The sheet to add the image to.

cellRef string

An A1-style cell reference for the image's top-left corner, e.g. "B2".

image byte[]

The image bytes. PNG and JPEG only, decided by magic bytes.

widthPixels int?

The image's width, in pixels. See AddImage(byte[], string, string, byte[], int?, int?).

heightPixels int?

The image's height, in pixels. See AddImage(byte[], string, string, byte[], int?, int?).

ct CancellationToken

Cancels the read and the write.

Returns

Task

Exceptions

ArgumentNullException

A path, a name or image is null.

ArgumentException

A path or a name is blank, image is empty, or the file at inputPath is empty.

ArgumentOutOfRangeException

A supplied size is zero or negative.

FileNotFoundException

inputPath does not exist.

DirectoryNotFoundException

inputPath's or outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, the reference is not valid, or the image is neither PNG nor JPEG.

AddPivotTable(byte[], string, string, string, string, IEnumerable<string>, IEnumerable<PivotDataField>, IEnumerable<string>?, IEnumerable<string>?, bool, bool)

Adds a pivot table to sheetName and returns the updated workbook.

public static byte[] AddPivotTable(byte[] xlsx, string sheetName, string sourceRange, string destinationCell, string name, IEnumerable<string> rowFields, IEnumerable<PivotDataField> dataFields, IEnumerable<string>? columnFields = null, IEnumerable<string>? pageFields = null, bool showRowGrandTotals = true, bool showColumnGrandTotals = true)

Parameters

xlsx byte[]

The workbook to add the pivot table to. It is not modified.

sheetName string

The sheet to add the pivot table to.

sourceRange string

An A1-style range naming the source data, e.g. "A1:C10".

destinationCell string

An A1-style cell reference for the pivot table's top-left corner, e.g. "E1".

name string

The pivot table's name.

rowFields IEnumerable<string>

Source column headers to group by, down the rows. At least one.

dataFields IEnumerable<PivotDataField>

The aggregated value columns. At least one.

columnFields IEnumerable<string>

Source column headers to group by, across the columns. Optional.

pageFields IEnumerable<string>

Source column headers used as report filters. Optional.

showRowGrandTotals bool

Whether to show a grand total row.

showColumnGrandTotals bool

Whether to show a grand total column.

Returns

byte[]

Remarks

The result grid is empty until Excel opens and recalculates it. A pivot table's aggregated values are computed by whichever application opens the file — nothing that WRITES it (this method included) populates the grid. This is a HARDER version of the limitation this package already documents for XlsxFormula: a formula's value is computed by ReadCell(byte[], string, string)/ReadSheet(byte[], string) on read, and, since XlsxToPdfConverter started calling Calculate() before rendering, is now computed there too — but there is no equivalent pivot-evaluation engine here, so reading the pivot's own cells back with ReadCell(byte[], string, string) immediately after calling this method returns empty strings, and XlsxToPdfConverter renders nothing where the pivot's results would be. Open the result in Excel (or an equivalent) to see it populated.

Further edits to the workbook through this class's other methods (all ClosedXML-based) re-serialize the pivot table's XML — measured directly — but its field structure and aggregation choices survive that re-serialization correctly.

Exceptions

ArgumentNullException

xlsx, rowFields, dataFields or another required argument is null.

ArgumentException

xlsx is empty, a name argument is blank, or rowFields/dataFields is empty.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or destinationCell is not a valid cell reference.

AddPivotTableAsync(Stream, string, string, string, string, IEnumerable<string>, IEnumerable<PivotDataField>, Stream, IEnumerable<string>?, IEnumerable<string>?, bool, bool, CancellationToken)

Reads a workbook from source, adds a pivot table, and writes the result to destination — see AddPivotTable(byte[], string, string, string, string, IEnumerable<string>, IEnumerable<PivotDataField>, IEnumerable<string>?, IEnumerable<string>?, bool, bool) for the parameters.

source is read to its end and destination is written; neither is disposed, closed or sought, and neither has to be seekable.

public static Task AddPivotTableAsync(Stream source, string sheetName, string sourceRange, string destinationCell, string name, IEnumerable<string> rowFields, IEnumerable<PivotDataField> dataFields, Stream destination, IEnumerable<string>? columnFields = null, IEnumerable<string>? pageFields = null, bool showRowGrandTotals = true, bool showColumnGrandTotals = true, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

sheetName string

The sheet to add the pivot table to.

sourceRange string

An A1-style range naming the source data, e.g. "A1:C10".

destinationCell string

An A1-style cell reference for the pivot table's top-left corner, e.g. "E1".

name string

The pivot table's name.

rowFields IEnumerable<string>

Source column headers to group by, down the rows. At least one.

dataFields IEnumerable<PivotDataField>

The aggregated value columns. At least one.

destination Stream

The stream the updated workbook is written to.

columnFields IEnumerable<string>

Source column headers to group by, across the columns. Optional.

pageFields IEnumerable<string>

Source column headers used as report filters. Optional.

showRowGrandTotals bool

Whether to show a grand total row.

showColumnGrandTotals bool

Whether to show a grand total column.

ct CancellationToken

Cancels the read, the edit and the write.

Returns

Task

Exceptions

ArgumentNullException

source, destination, rowFields or dataFields is null.

ArgumentException

source is not readable or held no bytes, a name is blank, or rowFields/dataFields is empty.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or destinationCell is not a valid cell reference.

AddPivotTableAsync(string, string, string, string, string, string, IEnumerable<string>, IEnumerable<PivotDataField>, IEnumerable<string>?, IEnumerable<string>?, bool, bool, CancellationToken)

Reads a workbook from inputPath, adds a pivot table, and writes the result to outputPath — see AddPivotTable(byte[], string, string, string, string, IEnumerable<string>, IEnumerable<PivotDataField>, IEnumerable<string>?, IEnumerable<string>?, bool, bool) for the parameters. The two paths may be the same file: the updated bytes are computed in full before outputPath is opened.

public static Task AddPivotTableAsync(string inputPath, string outputPath, string sheetName, string sourceRange, string destinationCell, string name, IEnumerable<string> rowFields, IEnumerable<PivotDataField> dataFields, IEnumerable<string>? columnFields = null, IEnumerable<string>? pageFields = null, bool showRowGrandTotals = true, bool showColumnGrandTotals = true, CancellationToken ct = default)

Parameters

inputPath string

The workbook to read.

outputPath string

Where to write the result. Overwritten if it exists.

sheetName string

The sheet to add the pivot table to.

sourceRange string

An A1-style range naming the source data, e.g. "A1:C10".

destinationCell string

An A1-style cell reference for the pivot table's top-left corner, e.g. "E1".

name string

The pivot table's name.

rowFields IEnumerable<string>

Source column headers to group by, down the rows. At least one.

dataFields IEnumerable<PivotDataField>

The aggregated value columns. At least one.

columnFields IEnumerable<string>

Source column headers to group by, across the columns. Optional.

pageFields IEnumerable<string>

Source column headers used as report filters. Optional.

showRowGrandTotals bool

Whether to show a grand total row.

showColumnGrandTotals bool

Whether to show a grand total column.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Exceptions

ArgumentNullException

A path, a name, rowFields or dataFields is null.

ArgumentException

A path or a name is blank, the file at inputPath is empty, or rowFields/dataFields is empty.

FileNotFoundException

inputPath does not exist.

DirectoryNotFoundException

inputPath's or outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or destinationCell is not a valid cell reference.

AppendRows(byte[], string, IEnumerable<IEnumerable<object?>>)

Appends rows to sheetName, starting immediately after its last used row, and returns the updated workbook. Every other sheet, and all existing formatting, is left as it was.

"Last used row" comes from ClosedXML's LastRowUsed(), which — like LastCellUsed() in ReadSheet(byte[], string) — ignores formatting but counts a cell comment as used even with no value. A comment on an otherwise-blank row far below the real data therefore pushes the append down to start after that row, leaving a gap rather than continuing immediately after the last row a caller would see as holding data.

Cell typing and culture rules are identical to Create(string, IEnumerable<IEnumerable<object?>>). A cell holding an XlsxFormula is written as a formula. An empty rows is a no-op that still returns a valid workbook.

public static byte[] AppendRows(byte[] xlsx, string sheetName, IEnumerable<IEnumerable<object?>> rows)

Parameters

xlsx byte[]
sheetName string
rows IEnumerable<IEnumerable<object>>

Returns

byte[]

Exceptions

ArgumentNullException

xlsx or rows is null.

ArgumentException

xlsx is empty; sheetName is blank, is longer than 31 characters, or contains one of : \ / ? * [ ]; or an element of rows is null.

DocumentConversionException

The sheet was not found, or the package could not be opened or edited.

AppendRowsAsync(Stream, string, IEnumerable<IEnumerable<object?>>, Stream, CancellationToken)

Reads a workbook from source, appends rows to sheetName, and writes the result to destination. See AppendRows(byte[], string, IEnumerable<IEnumerable<object?>>) for the semantics, including exactly what "last used row" means.

source is read to its end and destination is written; neither is disposed, closed or sought.

public static Task AppendRowsAsync(Stream source, string sheetName, IEnumerable<IEnumerable<object?>> rows, Stream destination, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

sheetName string

The sheet to append to.

rows IEnumerable<IEnumerable<object>>

The rows to append.

destination Stream

The stream the updated workbook is written to.

ct CancellationToken

Cancels the read, the edit and the write.

Returns

Task

Exceptions

ArgumentNullException

rows is null.

ArgumentException

source is not readable or held no bytes; destination is not writable; sheetName is blank, is longer than 31 characters, or contains one of : \ / ? * [ ]; or an element of rows is null.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The sheet was not found, or the package could not be opened or edited.

AppendRowsAsync(string, string, string, IEnumerable<IEnumerable<object?>>, CancellationToken)

Reads a workbook from inputPath, appends rows to sheetName, and writes the result to outputPath, overwriting any existing file. See AppendRows(byte[], string, IEnumerable<IEnumerable<object?>>) for the semantics, including exactly what "last used row" means.

public static Task AppendRowsAsync(string inputPath, string outputPath, string sheetName, IEnumerable<IEnumerable<object?>> rows, CancellationToken ct = default)

Parameters

inputPath string

The workbook to read.

outputPath string

Where to write the result. Overwritten if it exists.

sheetName string

The sheet to append to.

rows IEnumerable<IEnumerable<object>>

The rows to append.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Exceptions

ArgumentNullException

rows is null.

ArgumentException

inputPath or outputPath is blank; sheetName is blank, is longer than 31 characters, or contains one of : \ / ? * [ ]; or an element of rows is null.

FileNotFoundException

inputPath does not exist.

DirectoryNotFoundException

inputPath's or outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The sheet was not found, or the package could not be opened or edited.

Create(IEnumerable<XlsxSheet>)

Builds a workbook from sheets, one worksheet each, in sequence order. Content comes from data rather than a template, so there is no source file to edit.

Cell typing and culture rules are identical to Create(string, IEnumerable<IEnumerable<object?>>). A cell holding an XlsxFormula is written as a formula — see that type for the one limit worth knowing about cached values.

public static byte[] Create(IEnumerable<XlsxSheet> sheets)

Parameters

sheets IEnumerable<XlsxSheet>

Returns

byte[]

Examples

byte[] xlsx = WorkbookEditor.Create(new[]
{
    XlsxSheet.Named("Sales", new[]
    {
        new object?[] { "Region", "Q1" },
        new object?[] { "North", 1200 },
        new object?[] { "Total", XlsxFormula.From("=SUM(B2:B2)") },
    }),
});

Exceptions

ArgumentNullException

sheets is null.

ArgumentException

sheets is empty, contains a null element, or names the same sheet twice.

DocumentConversionException

The workbook could not be built.

Create(string, IEnumerable<IEnumerable<object?>>)

Creates a workbook with one sheet populated from rows.

Every built-in numeric type is written as a number so formulas such as SUM() pick it up; DateTime and DateOnly become dates, TimeOnly and TimeSpan become durations. Anything else is formatted with InvariantCulture, so the same code produces the same spreadsheet on every machine.

public static byte[] Create(string sheetName, IEnumerable<IEnumerable<object?>> rows)

Parameters

sheetName string
rows IEnumerable<IEnumerable<object>>

Returns

byte[]

Exceptions

ArgumentNullException

rows is null.

ArgumentException

sheetName is blank, is longer than 31 characters, or contains one of : \ / ? * [ ]; or a row is null.

DocumentConversionException

The workbook could not be built.

CreateAsync(IEnumerable<XlsxSheet>, Stream, CancellationToken)

Builds a workbook from sheets and writes it to destination. See Create(IEnumerable<XlsxSheet>) for the semantics — this overload applies identical logic.

destination is written, from its current position, and is not disposed, closed or sought.

public static Task CreateAsync(IEnumerable<XlsxSheet> sheets, Stream destination, CancellationToken ct = default)

Parameters

sheets IEnumerable<XlsxSheet>

The sheets to build the workbook from, one worksheet each.

destination Stream

The stream the workbook is written to.

ct CancellationToken

Cancels the build and the write to destination.

Returns

Task

Exceptions

ArgumentNullException

sheets or destination is null.

ArgumentException

sheets is empty, contains a null element, or names the same sheet twice; or destination is not writable.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be built or written.

CreateAsync(string, IEnumerable<IEnumerable<object?>>, Stream, CancellationToken)

Builds a workbook with one sheet populated from rows and writes it to destination. See Create(string, IEnumerable<IEnumerable<object?>>) for the exact typing and culture rules applied to each cell — this overload applies the identical logic, writing to destination instead of returning an array.

destination is written, from its current position, and is not disposed, closed or sought — it belongs to the caller, and may be write-only and forward-only, such as an HTTP response body.

public static Task CreateAsync(string sheetName, IEnumerable<IEnumerable<object?>> rows, Stream destination, CancellationToken ct = default)

Parameters

sheetName string

The name of the sheet to create.

rows IEnumerable<IEnumerable<object>>

The rows to populate it with.

destination Stream

The stream the workbook is written to.

ct CancellationToken

Cancels the build and the write to destination.

Returns

Task

Exceptions

ArgumentNullException

rows or destination is null.

ArgumentException

sheetName is blank, is longer than 31 characters, or contains one of : \ / ? * [ ]; a row is null; or destination is not writable.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be built or written.

CreateToFileAsync(IEnumerable<XlsxSheet>, string, CancellationToken)

Builds a workbook from sheets and writes it to outputPath, overwriting any existing file. See Create(IEnumerable<XlsxSheet>) for the semantics.

public static Task CreateToFileAsync(IEnumerable<XlsxSheet> sheets, string outputPath, CancellationToken ct = default)

Parameters

sheets IEnumerable<XlsxSheet>

The sheets to build the workbook from, one worksheet each.

outputPath string

Where to write the workbook. Overwritten if it exists.

ct CancellationToken

Cancels the write to outputPath.

Returns

Task

Exceptions

ArgumentNullException

sheets or outputPath is null.

ArgumentException

sheets is empty, contains a null element, or names the same sheet twice; or outputPath is blank.

DirectoryNotFoundException

outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be built or written.

CreateToFileAsync(string, IEnumerable<IEnumerable<object?>>, string, CancellationToken)

Builds a workbook with one sheet populated from rows and writes it to outputPath. See Create(string, IEnumerable<IEnumerable<object?>>) for the exact typing and culture rules applied to each cell — this overload applies the identical logic, writing to outputPath instead of returning an array.

Named CreateToFileAsync rather than a third CreateAsync overload: sheetName and rows come first, same as CreateAsync(string, IEnumerable<IEnumerable<object?>>, Stream, CancellationToken), but the destination is a string path instead of a Stream — the distinct name keeps which kind of destination a call writes to visible at the call site, rather than resting on the argument type alone.

public static Task CreateToFileAsync(string sheetName, IEnumerable<IEnumerable<object?>> rows, string outputPath, CancellationToken ct = default)

Parameters

sheetName string

The name of the sheet to create.

rows IEnumerable<IEnumerable<object>>

The rows to populate it with.

outputPath string

Where to write the workbook. Overwritten if it exists.

ct CancellationToken

Cancels the write to outputPath.

Returns

Task

Exceptions

ArgumentNullException

outputPath, sheetName or rows is null.

ArgumentException

outputPath is blank; sheetName is blank, is longer than 31 characters, or contains one of : \ / ? * [ ]; or a row is null.

DirectoryNotFoundException

outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be built.

EvaluateFormulas(byte[])

A copy of xlsx with every formula's computed value written into the file, not just held in memory.

public static byte[] EvaluateFormulas(byte[] xlsx)

Parameters

xlsx byte[]

Returns

byte[]

Remarks

XlsxFormula's own remarks explain why this is needed at all: a formula this package writes carries a formula and nothing else, so a reader that trusts a cached value rather than recalculating — a third-party tool, or this package's own XlsxToPdfConverter before it started calling this internally — sees the formula's source text where a value belongs. Excel itself is unaffected, because it recalculates on open by default; this exists for everything that is not Excel.

A formula XlsxFormulaInspection would report as unsupported is left exactly as it was — no plausible-looking value is invented for it. Call InspectFormulas(byte[]) first if that distinction matters to the caller.

Exceptions

ArgumentNullException

xlsx is null.

ArgumentException

xlsx is empty.

DocumentConversionException

The workbook could not be read or written.

EvaluateFormulasAsync(Stream, Stream, CancellationToken)

A copy of xlsx with every formula's computed value written into the file, not just held in memory.

public static Task EvaluateFormulasAsync(Stream source, Stream destination, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

destination Stream

The stream the evaluated workbook is written to.

ct CancellationToken

Cancels the read, the evaluation and the write.

Returns

Task

Remarks

source is read to its end and destination is written; neither is disposed, closed or sought, and neither has to be seekable.

Exceptions

ArgumentNullException

source or destination is null.

ArgumentException

source is not readable or held no bytes, or destination is not writable.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be read or written.

Format(byte[], string, XlsxFormat)

Applies format to sheetName and returns the workbook.

public static byte[] Format(byte[] xlsx, string sheetName, XlsxFormat format)

Parameters

xlsx byte[]

The workbook to format. It is not modified.

sheetName string

The sheet to format.

format XlsxFormat

The formatting to apply.

Returns

byte[]

Remarks

Formatting is applied to an existing workbook rather than being an argument to Create, so it composes with every way a workbook can arrive here — built by Create(string, IEnumerable<IEnumerable<object?>>), appended to, or handed in by a caller who never used this library to make it.

See XlsxFormat for the boundary: a CLOSED vocabulary rather than a small one, and what is still deliberately outside it.

Exceptions

ArgumentNullException

xlsx or format is null.

ArgumentException

xlsx is empty, or sheetName is blank.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or a rule or validation named a range the sheet rejects — a malformed one such as "B2:B1", or a column letter beyond the sheet's width. Ranges are checked by the library beneath rather than here, deliberately: a second range parser would be a second source of truth about what a range is.

FormatAsync(Stream, string, XlsxFormat, Stream, CancellationToken)

Reads a workbook from source, applies format to sheetName, and writes the result to destination.

Neither stream is disposed, closed or sought.

public static Task FormatAsync(Stream source, string sheetName, XlsxFormat format, Stream destination, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

sheetName string

The sheet to format.

format XlsxFormat

The formatting to apply.

destination Stream

The stream the workbook is written to.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Exceptions

ArgumentNullException

format is null, or a stream is null.

ArgumentException

A stream is unusable, source held no bytes, or sheetName is blank.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, or the sheet does not exist.

InspectFormulas(byte[])

Every formula xlsx carries, and whether each one is understood well enough to trust its value. See XlsxFormulaInspection for why this asks rather than assumes.

public static XlsxFormulaInspection InspectFormulas(byte[] xlsx)

Parameters

xlsx byte[]

Returns

XlsxFormulaInspection

Exceptions

ArgumentNullException

xlsx is null.

ArgumentException

xlsx is empty.

DocumentConversionException

The workbook could not be read.

InspectFormulasAsync(Stream, CancellationToken)

Every formula xlsx carries, and whether each one is understood well enough to trust its value. See XlsxFormulaInspection for why this asks rather than assumes.

public static Task<XlsxFormulaInspection> InspectFormulasAsync(Stream source, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

ct CancellationToken

Cancels the read.

Returns

Task<XlsxFormulaInspection>

Remarks

source is read to its end and is neither disposed, closed nor sought.

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be read.

InspectSignatures(byte[])

Inspects xlsx for digital signatures — whether it carries one, how many, and who claims to have signed it. Does not validate anything cryptographically; see ValidateSignatures(byte[], DocumentSignatureValidationOptions?).

public static DocumentSignatureInfo InspectSignatures(byte[] xlsx)

Parameters

xlsx byte[]

Returns

DocumentSignatureInfo

Exceptions

ArgumentNullException

xlsx is null.

ArgumentException

xlsx is empty.

DocumentConversionException

The workbook could not be inspected.

InspectSignaturesAsync(Stream, CancellationToken)

Reads an .xlsx from source and inspects it for digital signatures — see InspectSignatures(byte[]). source is read to its end and is neither disposed, closed nor sought.

public static Task<DocumentSignatureInfo> InspectSignaturesAsync(Stream source, CancellationToken ct = default)

Parameters

source Stream
ct CancellationToken

Returns

Task<DocumentSignatureInfo>

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be inspected.

IsProtected(byte[])

Whether xlsx is an ENCRYPTED Office document.

public static bool IsProtected(byte[] xlsx)

Parameters

xlsx byte[]

The bytes to inspect.

Returns

bool

Remarks

This is not a validity check, and a false is not a promise that anything else will succeed. It distinguishes an encrypted document from a plain one; input that is neither — an image, a PDF, a text file, random bytes — is not encrypted, so this answers false for it, while every other method on this class refuses it. Measured over real files: a JPEG and a PDF both return false here and both throw from ExtractText.

The summary used to say "that is, whether the other methods on this class will refuse it". That reads as a guard — test it, and if false, proceed — and takes the wrong branch for every input that is not a document at all. The behaviour was always right and only the sentence was wrong, which is why the fix is here and not in the code.

Reads the file signature; it does not try the password and does not need one. A plain XLSX is a ZIP package, an encrypted one is a compound file, and the two are distinguishable from their first eight bytes.

Exceptions

ArgumentNullException

xlsx is null.

IsProtectedAsync(Stream, CancellationToken)

Whether xlsx is an ENCRYPTED Office document.

public static Task<bool> IsProtectedAsync(Stream source, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

ct CancellationToken

Cancels the read.

Returns

Task<bool>

Remarks

source is read to its end and is neither disposed, closed nor sought. Unlike IsProtected(byte[]), which answers false for an empty array, an empty source is rejected — every Stream overload in this package treats a source that held no bytes as a caller error rather than as content.

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes.

OperationCanceledException

ct was cancelled.

Protect(byte[], string)

A copy of xlsx encrypted with password, so it cannot be opened without one.

public static byte[] Protect(byte[] xlsx, string password)

Parameters

xlsx byte[]

The workbook to encrypt.

password string

The password required to open the result. May not be empty.

Returns

byte[]

Remarks

This is file encryption, not workbook protection. Office offers both under the same menu and they are not the same thing: this scrambles the whole file, so nothing can be read without the password. The other kind - a flag asking a reader not to edit - is a request rather than a lock, and is deliberately not exposed here.

The result is not a XLSX package any more. An encrypted Office document is a compound file with the package sealed inside it, so every other method on this class refuses it - call Unprotect(byte[], string) first. That refusal is the honest behaviour: those methods could not read the content even if they tried.

Exceptions

ArgumentNullException

xlsx or password is null.

ArgumentException

xlsx is empty, or password is empty.

DocumentConversionException

The workbook could not be read or encrypted.

ProtectAsync(Stream, Stream, string, CancellationToken)

Reads a workbook from source and writes the encrypted copy to destination.

Neither stream is disposed, closed or sought.

public static Task ProtectAsync(Stream source, Stream destination, string password, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

destination Stream

The stream the encrypted workbook is written to.

password string

The password required to open the result. May not be empty.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Remarks

This is file encryption, not workbook protection. Office offers both under the same menu and they are not the same thing: this scrambles the whole file, so nothing can be read without the password. The other kind - a flag asking a reader not to edit - is a request rather than a lock, and is deliberately not exposed here.

The result is not a XLSX package any more. An encrypted Office document is a compound file with the package sealed inside it, so every other method on this class refuses it - call Unprotect(byte[], string) first. That refusal is the honest behaviour: those methods could not read the content even if they tried.

ReadCell(byte[], string, string)

Reads a cell as a string. cellRef is an A1-style reference. Text follows the calling thread's CurrentCulture — see ReadSheet(byte[], string) for the full rule.

public static string ReadCell(byte[] xlsx, string sheetName, string cellRef)

Parameters

xlsx byte[]
sheetName string
cellRef string

Returns

string

Exceptions

ArgumentNullException

Any argument is null.

ArgumentException

xlsx is empty, or a name is blank.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

ReadCellAsync(Stream, string, string, CancellationToken)

Reads a workbook from source and returns a cell as a string. cellRef is an A1-style reference. source is read to its end and is neither disposed, closed nor sought.

public static Task<string> ReadCellAsync(Stream source, string sheetName, string cellRef, CancellationToken ct = default)

Parameters

source Stream
sheetName string
cellRef string
ct CancellationToken

Returns

Task<string>

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes, or a name is blank.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

ReadCellAsync(string, string, string, CancellationToken)

Reads a workbook from path and returns a cell as a string. cellRef is an A1-style reference. See ReadCell(byte[], string, string) for the culture rule applied to the text.

public static Task<string> ReadCellAsync(string path, string sheetName, string cellRef, CancellationToken ct = default)

Parameters

path string

The workbook to read.

sheetName string

The sheet containing the cell.

cellRef string

An A1-style cell reference, e.g. "B2".

ct CancellationToken

Cancels the read.

Returns

Task<string>

The cell's value as a string.

Exceptions

ArgumentNullException

A path or a name is null.

ArgumentException

path or a name is blank, or the file it names is empty.

FileNotFoundException

path does not exist.

DirectoryNotFoundException

path's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

ReadMetadata(byte[])

The document properties xlsx carries.

public static DocumentMetadata ReadMetadata(byte[] xlsx)

Parameters

xlsx byte[]

Returns

DocumentMetadata

Exceptions

ArgumentNullException

xlsx is null.

ArgumentException

xlsx is empty.

DocumentConversionException

The workbook could not be read.

ReadMetadataAsync(Stream, CancellationToken)

The document properties xlsx carries.

public static Task<DocumentMetadata> ReadMetadataAsync(Stream source, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

ct CancellationToken

Cancels the read.

Returns

Task<DocumentMetadata>

Remarks

source is read to its end and is neither disposed, closed nor sought.

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be read.

ReadSheet(byte[], string)

Reads a whole sheet as strings, anchored at A1: if the data starts at C3, its first value is at rows[2][2]. Every row is padded to the last used column, so all rows have the same length; blank cells — and entirely blank rows inside the range — come back as empty strings rather than being dropped, which keeps rows[r][c] positionally meaningful.

Values are produced exactly as ReadCell(byte[], string, string) produces them, so the two can never disagree about what a cell says. A formula cell reads back one of two ways, and which one depends on the file rather than on this library:

  • If the file carries a cached value, as one Excel has saved does, that cached value is returned and the formula is not evaluated. It can therefore be stale — a workbook whose inputs were edited by something that did not recalculate reports the old result.
  • If it does not — which is what this library writes, see XlsxFormula — ClosedXML evaluates the formula on read, so a cell holding =A1+A2 over 1 and 2 reads back as "3", and one that cannot be evaluated reads back as its Excel error string (#DIV/0!, #NAME?, #REF!) rather than throwing.

Text follows the calling thread's CurrentCulture — the same rule ReadCell(byte[], string, string) uses, and asymmetric with Create(string, IEnumerable<IEnumerable<object?>>), which deliberately writes with InvariantCulture so the same code produces the same file everywhere. A number such as 1234.5 reads back as "1234.5" under an invariant or en-US culture but "1234,5" under de-DE; callers who parse the returned text as a number should account for that, e.g. by parsing with an explicit CultureInfo rather than the default.

public static IReadOnlyList<IReadOnlyList<string>> ReadSheet(byte[] xlsx, string sheetName)

Parameters

xlsx byte[]

The workbook bytes.

sheetName string

The sheet to read.

Returns

IReadOnlyList<IReadOnlyList<string>>

The sheet's used range, anchored at A1 and padded rectangular. Empty only if the sheet holds no values and no cell comments: formatting alone never widens the range, but a comment on an otherwise-blank cell does, because ClosedXML's LastCellUsed() counts it as used.

Examples

// No need to know the workbook's shape in advance.
foreach (string name in WorkbookEditor.SheetNames(xlsx))
{
    IReadOnlyList<IReadOnlyList<string>> grid = WorkbookEditor.ReadSheet(xlsx, name);
    Console.WriteLine($"{name}: {grid.Count} rows x {grid[0].Count} columns");
}

Remarks

The whole range is materialised into memory at once, so its cost is proportional to rows × columns, not to how much of that rectangle actually holds data. To keep one far-flung stray value from exhausting memory, ReadSheet(byte[], string) throws DocumentConversionException rather than allocate when the used range exceeds 2,000,000 cells.

Exceptions

ArgumentNullException

Any argument is null.

ArgumentException

xlsx is empty, or sheetName is blank.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the sheet's used range exceeds the 2,000,000-cell limit ReadSheet(byte[], string) will materialise.

ReadSheetAsync(Stream, string, CancellationToken)

Reads a workbook from source and returns a whole sheet as strings. See ReadSheet(byte[], string) for the anchoring, padding, culture and formula rules — this overload applies the identical logic. source is read to its end and is neither disposed, closed nor sought.

public static Task<IReadOnlyList<IReadOnlyList<string>>> ReadSheetAsync(Stream source, string sheetName, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

sheetName string

The sheet to read.

ct CancellationToken

Cancels the read.

Returns

Task<IReadOnlyList<IReadOnlyList<string>>>

The sheet's used range, anchored at A1 and padded rectangular. Empty only if the sheet holds no values and no cell comments — see ReadSheet(byte[], string).

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes, or sheetName is blank.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the sheet's used range exceeds the 2,000,000-cell limit ReadSheet(byte[], string) will materialise.

ReadSheetAsync(string, string, CancellationToken)

Reads a workbook from path and returns a whole sheet as strings. See ReadSheet(byte[], string) for the anchoring, padding, culture and formula rules — this overload applies the identical logic.

public static Task<IReadOnlyList<IReadOnlyList<string>>> ReadSheetAsync(string path, string sheetName, CancellationToken ct = default)

Parameters

path string

The workbook to read.

sheetName string

The sheet to read.

ct CancellationToken

Cancels the read.

Returns

Task<IReadOnlyList<IReadOnlyList<string>>>

The sheet's used range, anchored at A1 and padded rectangular. Empty only if the sheet holds no values and no cell comments — see ReadSheet(byte[], string).

Exceptions

ArgumentNullException

A path or sheetName is null.

ArgumentException

path or sheetName is blank, or the file at path is empty.

FileNotFoundException

path does not exist.

DirectoryNotFoundException

path's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the sheet's used range exceeds the 2,000,000-cell limit ReadSheet(byte[], string) will materialise.

SetCell(byte[], string, string, object?)

Sets a cell and returns the updated workbook bytes. A cell holding an XlsxFormula is written as a formula instead of a literal value — see that type for the one limit worth knowing about cached values.

public static byte[] SetCell(byte[] xlsx, string sheetName, string cellRef, object? value)

Parameters

xlsx byte[]
sheetName string
cellRef string
value object

Returns

byte[]

Exceptions

ArgumentNullException

Any argument other than value is null.

ArgumentException

xlsx is empty, or a name is blank.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

SetCellAsync(Stream, string, string, object?, Stream, CancellationToken)

Reads a workbook from source, sets one cell, and writes the result to destination. cellRef is an A1-style reference. A cell holding an XlsxFormula is written as a formula instead of a literal value — see that type for the one limit worth knowing about cached values.

source is read to its end and destination is written; neither is disposed, closed or sought, and neither has to be seekable.

public static Task SetCellAsync(Stream source, string sheetName, string cellRef, object? value, Stream destination, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

sheetName string

The sheet containing the cell.

cellRef string

An A1-style cell reference, e.g. "B2".

value object

The value to write. null clears the cell; an XlsxFormula writes a formula.

destination Stream

The stream the updated workbook is written to.

ct CancellationToken

Cancels the read, the edit and the write.

Returns

Task

Exceptions

ArgumentNullException

source or destination is null.

ArgumentException

source is not readable or held no bytes, a name is blank, or destination is not writable.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

SetCellAsync(string, string, string, string, object?, CancellationToken)

Reads a workbook from inputPath, sets one cell, and writes the result to outputPath. cellRef is an A1-style reference. A cell holding an XlsxFormula is written as a formula instead of a literal value — see that type for the one limit worth knowing about cached values. The two paths may be the same file: the updated bytes are computed in full before outputPath is opened, so a workbook that fails to process — cannot be read, or cannot be edited — leaves outputPath untouched. That guarantee does not extend to a failure during the write itself: a full disk, a cancellation, or the process dying mid-write can still leave a partial file, so in-place editing of an irreplaceable workbook is not crash-safe.

public static Task SetCellAsync(string inputPath, string outputPath, string sheetName, string cellRef, object? value, CancellationToken ct = default)

Parameters

inputPath string

The workbook to read.

outputPath string

Where to write the result. Overwritten if it exists.

sheetName string

The sheet containing the cell.

cellRef string

An A1-style cell reference, e.g. "B2".

value object

The value to write. null clears the cell; an XlsxFormula writes a formula.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Exceptions

ArgumentNullException

A path or a name is null.

ArgumentException

A path or a name is blank, or the file at inputPath is empty.

FileNotFoundException

inputPath does not exist.

DirectoryNotFoundException

inputPath's or outputPath's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened, the sheet does not exist, or the reference is not valid.

SheetNames(byte[])

Lists every sheet in the workbook, in tab order, including hidden sheets — hiding a sheet is a presentation choice, not a privacy boundary, and a caller who cannot see a hidden sheet listed has no way to discover it exists.

public static IReadOnlyList<string> SheetNames(byte[] xlsx)

Parameters

xlsx byte[]

The workbook bytes.

Returns

IReadOnlyList<string>

The sheet names, in tab order.

Exceptions

ArgumentNullException

xlsx is null.

ArgumentException

xlsx is empty.

DocumentConversionException

The workbook could not be opened.

SheetNamesAsync(Stream, CancellationToken)

Reads a workbook from source and lists every sheet in tab order, including hidden sheets. source is read to its end and is neither disposed, closed nor sought.

public static Task<IReadOnlyList<string>> SheetNamesAsync(Stream source, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

ct CancellationToken

Cancels the read.

Returns

Task<IReadOnlyList<string>>

The sheet names, in tab order.

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened.

SheetNamesAsync(string, CancellationToken)

Reads a workbook from path and lists every sheet in tab order, including hidden sheets. See SheetNames(byte[]) for the full rule.

public static Task<IReadOnlyList<string>> SheetNamesAsync(string path, CancellationToken ct = default)

Parameters

path string

The workbook to read.

ct CancellationToken

Cancels the read.

Returns

Task<IReadOnlyList<string>>

The sheet names, in tab order.

Exceptions

ArgumentNullException

path is null.

ArgumentException

path is blank, or the file it names is empty.

FileNotFoundException

path does not exist.

DirectoryNotFoundException

path's directory does not exist.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be opened.

Unprotect(byte[], string)

A copy of xlsx with its encryption removed, so the rest of this class can work on it.

public static byte[] Unprotect(byte[] xlsx, string password)

Parameters

xlsx byte[]

The encrypted workbook.

password string

The password the workbook was encrypted with.

Returns

byte[]

Remarks

The output is not protected in any way. That is what was asked for, but the bytes this returns are readable by anyone who obtains them.

A workbook that was never encrypted is reported as such rather than passed through, because silently returning the input would make a broken pipeline look like a working one.

Exceptions

ArgumentNullException

xlsx or password is null.

ArgumentException

xlsx is empty, or password is empty.

DocumentConversionException

The password was wrong, the workbook was not encrypted, or it could not be read.

UnprotectAsync(Stream, Stream, string, CancellationToken)

Reads an encrypted workbook from source and writes the unprotected copy to destination.

Neither stream is disposed, closed or sought.

public static Task UnprotectAsync(Stream source, Stream destination, string password, CancellationToken ct = default)

Parameters

source Stream

The stream the encrypted workbook is read from.

destination Stream

The stream the unprotected workbook is written to.

password string

The password the workbook was encrypted with.

ct CancellationToken

Cancels the read and the write.

Returns

Task

Remarks

The output is not protected in any way. That is what was asked for, but the bytes this returns are readable by anyone who obtains them.

A workbook that was never encrypted is reported as such rather than passed through, because silently returning the input would make a broken pipeline look like a working one.

ValidateSignatures(byte[], DocumentSignatureValidationOptions?)

Validates every digital signature xlsx carries, returning the report-level tamper-detection verdict alongside each signature's own certificate chain trust and revocation status. Read DocumentSignatureValidationResult's own remarks before treating its CryptographicStatus as tamper detection — it is not; the report-level IsCryptographicallyValid is. Never performs revocation checking or certificate downloads over the network, regardless of options — see DocumentSignatureValidationOptions's own remarks.

public static DocumentSignatureValidationReport ValidateSignatures(byte[] xlsx, DocumentSignatureValidationOptions? options = null)

Parameters

xlsx byte[]
options DocumentSignatureValidationOptions

Returns

DocumentSignatureValidationReport

Exceptions

ArgumentNullException

xlsx is null.

ArgumentException

xlsx is empty.

DocumentConversionException

The workbook could not be validated.

ValidateSignaturesAsync(Stream, DocumentSignatureValidationOptions?, CancellationToken)

Reads an .xlsx from source and validates its digital signatures — see ValidateSignatures(byte[], DocumentSignatureValidationOptions?). source is read to its end and is neither disposed, closed nor sought.

public static Task<DocumentSignatureValidationReport> ValidateSignaturesAsync(Stream source, DocumentSignatureValidationOptions? options = null, CancellationToken ct = default)

Parameters

source Stream
options DocumentSignatureValidationOptions
ct CancellationToken

Returns

Task<DocumentSignatureValidationReport>

Exceptions

ArgumentNullException

source is null.

ArgumentException

source is not readable or held no bytes.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be validated.

WithMetadata(byte[], DocumentMetadata)

A copy of xlsx carrying metadata.

public static byte[] WithMetadata(byte[] xlsx, DocumentMetadata metadata)

Parameters

xlsx byte[]
metadata DocumentMetadata

Returns

byte[]

Remarks

A null property leaves what the workbook already had in place, so stamping a title does not silently erase an author. Pass an empty string to clear one.

Exceptions

ArgumentNullException

xlsx or metadata is null.

ArgumentException

xlsx is empty.

DocumentConversionException

The workbook could not be read or written.

WithMetadataAsync(Stream, DocumentMetadata, Stream, CancellationToken)

A copy of xlsx carrying metadata.

public static Task WithMetadataAsync(Stream source, DocumentMetadata metadata, Stream destination, CancellationToken ct = default)

Parameters

source Stream

The stream the workbook is read from.

metadata DocumentMetadata

The properties to stamp.

destination Stream

The stream the updated workbook is written to.

ct CancellationToken

Cancels the read, the edit and the write.

Returns

Task

Remarks

source is read to its end and destination is written; neither is disposed, closed or sought, and neither has to be seekable.

Exceptions

ArgumentNullException

source, metadata or destination is null.

ArgumentException

source is not readable or held no bytes, or destination is not writable.

OperationCanceledException

ct was cancelled.

DocumentConversionException

The workbook could not be read or written.