In the 2025 version of the Documents packages, "TimeSpan? timeout" were added to a number of interfaces, with the old versions obsoleted, for example: IWorkbookFormatProvider.Import & IWorkbookFormatProvider.Export.
This is a very strange choice, because this limits the flexibility of the interfaces for no reason at all. By only providing the TimeSpan parameter and not a CancellationToken is currently impossible to cancel the operation because e.g. an API request was canceled.
Internally these methods are implemented by first creating a cancellation token using
using CancellationTokenSource cancellationTokenSource = CancelationTokenSourceFactory.CreateTokenSource(timeout);
the token from this CancellationTokenSource is then passed to a protected method. Because this internal method uses a CancellationToken anyway, there is practically 0 development cost to exposing this in the interface, which makes the choice not to do so even more confusing.
The interfaces should expose methods that take a CancellationToken instead of a TimeSpan. This would allow for the same functionality as the TimeSpan parameter, by simply passing a cancellation token with a CancelAfter set with a TimeSpan, and an extension method could be provided for the interface which does exactly that, so users can still call these methods with a TimeSpan parameter if they wish to do so for convenience.
Please, in the next version, make these interfaces methods like this:
Workbook Import(Stream input, CancellationToken cancellationToken = default);
void Export(Workbook workbook, Stream output, CancellationToken cancellationToken = default);
and, for convenience, add extension methods for these like this:
public static class WorkbookFormatProviderExtensions
{
public static Workbook Import(this IWorkbookFormatProvider workbookFormatProvider, Stream input, TimeSpan? timeout)
{
using CancellationTokenSource cancellationTokenSource = CancelationTokenSourceFactory.CreateTokenSource(timeout);
return workbookFormatProvider.Import(input, cancellationTokenSource.Token);
}
}
Affected interfaces I've run into so far:
There may be more with this same pattern, I haven't checked.
string inputFileName = "input.xlsx";
if (!File.Exists(inputFileName))
{
throw new FileNotFoundException(String.Format("File {0} was not found!", inputFileName));
}
Telerik.Windows.Documents.Spreadsheet.Model.Workbook workbook;
IWorkbookFormatProvider formatProvider = new Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml.Xlsx.XlsxFormatProvider();
using (Stream input = new FileStream(inputFileName, FileMode.Open))
{
workbook = formatProvider.Import(input, TimeSpan.MaxValue);
}
string outputFilePath = "output.xlsx";
using (Stream output = new FileStream(outputFilePath, FileMode.Create))
{
formatProvider.Export(workbook, output, TimeSpan.MaxValue);
}
Process.Start(new ProcessStartInfo() { FileName = outputFilePath, UseShellExecute = true });
Read the documentation for CancelationTokenSource.CancelAfter:
this method will throw an ArgumentOutOfRangeException when: delay.TotalMilliseconds is less than -1 or greater than Int32.MaxValue (or UInt32.MaxValue - 1 on some versions of .NET). Note that this upper bound is more restrictive than TimeSpan.MaxValue.
----------------------------------------------------
your code in CancelationTokenSourceFactory.CreateTokenSource does this check:
if (timeSpan.HasValue && timeSpan.Value != TimeSpan.MaxValue)
this check for TimeSpan.MaxValue seems totally pointless here, if timeSpan is anything between ~2147483647 and 922337203685476 milliseconds long this will still just throw a ArgumentOutOfRangeException.
I suspect that this check was intended as a way to prevent creating a cancellation timer that never triggers in the CancellationTokenSource, which should look like this:
if (timeSpan.HasValue && timeSpan != Timeout.InfiniteTimeSpan) //Timeout.InfiniteTimeSpan is -1 milliseconds
NullReferenceException when inserting a document containing a table with a document variable having a line break (\n) in its value.
Add support for pivot tables.
at System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument) at System.Collections.Generic.Dictionary`2.FindValue(TKey key) at System.Collections.Generic.Dictionary`2.ContainsKey(TKey key) at Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml.Xlsx.Model.Elements.Worksheets.ConditionalFormattingRuleElementX14.OnAfterRead(IXlsxWorksheetImportContext context) in C:\Work\document-processing\Documents\Spreadsheet\FormatProviders\OpenXml\Xlsx\Model\Elements\Worksheets\ConditionalFormatting\x14\ConditionalFormattingRuleElementX14.cs:line 62
Purpose: Long-term archiving of electronic documents with full semantic structure.
Level "1a" ensures:
Tagged PDF (with proper logical structure and reading order)
Unicode text for proper text extraction and searchability
Embedded fonts (for consistent rendering)
Restrictions:
No audio/video
No encryption
No JavaScript
No external content (everything must be self-contained)
Based on: PDF 1.4 (Acrobat 5)