1- using System . ComponentModel ;
2- using System . Xml . Linq ;
31using MiniExcelLib . Core . OpenXml . Constants ;
42using MiniExcelLib . Core . OpenXml . Models ;
53using MiniExcelLib . Core . OpenXml . Styles . Builder ;
64using MiniExcelLib . Core . OpenXml . Zip ;
75using MiniExcelLib . Core . WriteAdapters ;
6+ using System . ComponentModel ;
7+ using System . Xml . Linq ;
88
99namespace MiniExcelLib . Core . OpenXml ;
1010
1111internal partial class OpenXmlWriter : IMiniExcelWriter
1212{
1313 private static readonly UTF8Encoding Utf8WithBom = new ( true ) ;
14-
14+
1515 private readonly MiniExcelZipArchive _archive ;
1616 private readonly OpenXmlConfiguration _configuration ;
1717 private readonly Stream _stream ;
1818 private readonly List < SheetDto > _sheets = [ ] ;
1919 private readonly List < FileDto > _files = [ ] ;
20-
20+
2121 private readonly string ? _defaultSheetName ;
2222 private readonly bool _printHeader ;
2323 private readonly object ? _value ;
@@ -41,16 +41,16 @@ internal OpenXmlWriter(Stream stream, object? value, string? sheetName, IMiniExc
4141 _printHeader = printHeader ;
4242 _defaultSheetName = sheetName ;
4343 }
44-
44+
4545 [ CreateSyncVersion ]
46- internal static Task < OpenXmlWriter > CreateAsync ( Stream stream , object ? value , string ? sheetName , bool printHeader , IMiniExcelConfiguration ? configuration , CancellationToken cancellationToken = default )
46+ internal static Task < OpenXmlWriter > CreateAsync ( Stream stream , object ? value , string ? sheetName , bool printHeader , IMiniExcelConfiguration ? configuration , CancellationToken cancellationToken = default )
4747 {
4848 ThrowHelper . ThrowIfInvalidSheetName ( sheetName ) ;
49-
49+
5050 var writer = new OpenXmlWriter ( stream , value , sheetName , configuration , printHeader ) ;
5151 return Task . FromResult ( writer ) ;
5252 }
53-
53+
5454 [ CreateSyncVersion ]
5555 public async Task < int [ ] > SaveAsAsync ( IProgress < int > ? progress = null , CancellationToken cancellationToken = default )
5656 {
@@ -190,7 +190,7 @@ private async Task<int> CreateSheetXmlAsync(object? values, string sheetPath, IP
190190 using var zipStream = entry . Open ( ) ;
191191#endif
192192 using var writer = new SafeStreamWriter ( zipStream , Utf8WithBom , _configuration . BufferSize ) ;
193-
193+
194194 if ( values is null )
195195 {
196196 await WriteEmptySheetAsync ( writer ) . ConfigureAwait ( false ) ;
@@ -241,125 +241,136 @@ private async Task<int> WriteValuesAsync(SafeStreamWriter writer, object values,
241241 {
242242 writeAdapter = MiniExcelWriteAdapterFactory . GetWriteAdapter ( values , _configuration ) ;
243243 }
244+ try
245+ {
246+ var count = 0 ;
247+ var isKnownCount = writeAdapter is not null && writeAdapter . TryGetKnownCount ( out count ) ;
244248
245- var count = 0 ;
246- var isKnownCount = writeAdapter is not null && writeAdapter . TryGetKnownCount ( out count ) ;
247-
248249#if SYNC_ONLY
249250 var props = writeAdapter ? . GetColumns ( ) ;
250251#else
251- var props = writeAdapter is not null
252- ? writeAdapter . GetColumns ( )
253- : await ( asyncWriteAdapter ? . GetColumnsAsync ( ) ?? Task . FromResult < List < MiniExcelColumnInfo > ? > ( null ) ) . ConfigureAwait ( false ) ;
252+ var props = writeAdapter is not null
253+ ? writeAdapter . GetColumns ( )
254+ : await ( asyncWriteAdapter ? . GetColumnsAsync ( ) ?? Task . FromResult < List < MiniExcelColumnInfo > ? > ( null ) ) . ConfigureAwait ( false ) ;
254255#endif
255-
256- if ( props is null)
257- {
258- await WriteEmptySheetAsync ( writer ) . ConfigureAwait ( false ) ;
259- return 0 ;
260- }
261-
262- int maxRowIndex ;
263- var maxColumnIndex = props . Count ( x => x is { ExcelIgnore : false } ) ;
264256
265- await writer . WriteAsync ( WorksheetXml . StartWorksheetWithRelationship , cancellationToken ) . ConfigureAwait ( false ) ;
257+ if ( props is null )
258+ {
259+ await WriteEmptySheetAsync( writer ) . ConfigureAwait ( false ) ;
260+ return 0 ;
261+ }
266262
267- long dimensionPlaceholderPostition = 0 ;
263+ int maxRowIndex;
264+ var maxColumnIndex = props. Count ( x => x is { ExcelIgnore : false } ) ;
268265
269- // We can write the dimensions directly if the row count is known
270- if ( isKnownCount )
271- {
272- maxRowIndex = _printHeader ? count + 1 : count ;
273- await writer . WriteAsync ( WorksheetXml . Dimension ( GetDimensionRef ( maxRowIndex , props . Count ) ) , cancellationToken ) . ConfigureAwait ( false ) ;
274- }
275- else if ( _configuration . FastMode )
276- {
277- dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync ( writer ) . ConfigureAwait ( false ) ;
278- }
266+ await writer. WriteAsync ( WorksheetXml . StartWorksheetWithRelationship , cancellationToken ) . ConfigureAwait ( false ) ;
279267
280- //sheet view
281- await writer . WriteAsync ( GetSheetViews ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
268+ long dimensionPlaceholderPostition = 0 ;
282269
283- //cols:width
284- ExcelWidthCollection ? widths = null ;
285- long columnWidthsPlaceholderPosition = 0 ;
286- if ( _configuration . EnableAutoWidth )
287- {
288- columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync ( writer , maxColumnIndex , cancellationToken ) . ConfigureAwait ( false ) ;
289- widths = new ExcelWidthCollection ( _configuration . MinWidth , _configuration . MaxWidth , props ) ;
290- }
291- else
292- {
293- await WriteColumnsWidthsAsync ( writer , ExcelColumnWidth . FromProps ( props ) , cancellationToken ) . ConfigureAwait ( false ) ;
294- }
270+ // We can write the dimensions directly if the row count is known
271+ if ( isKnownCount )
272+ {
273+ maxRowIndex = _printHeader ? count + 1 : count ;
274+ await writer . WriteAsync ( WorksheetXml . Dimension ( GetDimensionRef ( maxRowIndex , props . Count ) ) , cancellationToken ) . ConfigureAwait ( false ) ;
275+ }
276+ else if ( _configuration . FastMode )
277+ {
278+ dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync ( writer ) . ConfigureAwait ( false ) ;
279+ }
295280
296- //header
297- await writer . WriteAsync ( WorksheetXml . StartSheetData , cancellationToken ) . ConfigureAwait ( false ) ;
298- var currentRowIndex = 0 ;
299- if ( _printHeader )
300- {
301- await PrintHeaderAsync ( writer , props ! , cancellationToken ) . ConfigureAwait ( false ) ;
302- currentRowIndex++ ;
303- }
281+ //sheet view
282+ await writer . WriteAsync ( GetSheetViews ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
304283
305- if ( writeAdapter is not null )
306- {
307- foreach ( var row in writeAdapter . GetRows ( props , cancellationToken ) )
284+ //cols:width
285+ ExcelWidthCollection ? widths = null ;
286+ long columnWidthsPlaceholderPosition = 0 ;
287+ if ( _configuration . EnableAutoWidth )
308288 {
309- cancellationToken. ThrowIfCancellationRequested ( ) ;
289+ columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync ( writer , maxColumnIndex , cancellationToken ) . ConfigureAwait ( false ) ;
290+ widths = new ExcelWidthCollection ( _configuration . MinWidth , _configuration . MaxWidth , props ) ;
291+ }
292+ else
293+ {
294+ await WriteColumnsWidthsAsync ( writer , ExcelColumnWidth . FromProps ( props ) , cancellationToken ) . ConfigureAwait ( false ) ;
295+ }
310296
311- await writer. WriteAsync ( WorksheetXml . StartRow ( ++ currentRowIndex ) , cancellationToken ) . ConfigureAwait ( false ) ;
312- foreach ( var cellValue in row)
297+ //header
298+ await writer . WriteAsync ( WorksheetXml . StartSheetData , cancellationToken ) . ConfigureAwait ( false ) ;
299+ var currentRowIndex = 0 ;
300+ if ( _printHeader )
301+ {
302+ await PrintHeaderAsync ( writer , props ! , cancellationToken ) . ConfigureAwait ( false ) ;
303+ currentRowIndex++ ;
304+ }
305+
306+ if ( writeAdapter is not null )
307+ {
308+ foreach ( var row in writeAdapter . GetRows ( props , cancellationToken ) )
313309 {
314310 cancellationToken . ThrowIfCancellationRequested ( ) ;
315- await WriteCellAsync( writer , currentRowIndex , cellValue . CellIndex , cellValue . Value , cellValue . Prop , widths ) . ConfigureAwait ( false ) ;
316- progress? . Report ( 1 ) ;
311+
312+ await writer . WriteAsync ( WorksheetXml . StartRow ( ++ currentRowIndex ) , cancellationToken ) . ConfigureAwait ( false ) ;
313+ foreach ( var cellValue in row)
314+ {
315+ cancellationToken . ThrowIfCancellationRequested ( ) ;
316+ await WriteCellAsync ( writer , currentRowIndex , cellValue . CellIndex , cellValue . Value , cellValue . Prop , widths ) . ConfigureAwait ( false ) ;
317+ progress ? . Report ( 1 ) ;
318+ }
319+ await writer. WriteAsync ( WorksheetXml . EndRow , cancellationToken ) . ConfigureAwait ( false ) ;
317320 }
318- await writer. WriteAsync ( WorksheetXml . EndRow , cancellationToken ) . ConfigureAwait ( false ) ;
319321 }
320- }
321- else
322- {
323- #if ! SYNC_ONLY
324- await foreach ( var row in asyncWriteAdapter . GetRowsAsync ( props , cancellationToken ) . ConfigureAwait ( false ) )
322+ else
325323 {
326- cancellationToken. ThrowIfCancellationRequested ( ) ;
327- await writer. WriteAsync ( WorksheetXml . StartRow ( ++ currentRowIndex ) , cancellationToken ) . ConfigureAwait ( false ) ;
328-
329- await foreach ( var cellValue in row. ConfigureAwait ( false ) . WithCancellation ( cancellationToken ) )
324+ #if ! SYNC_ONLY
325+ await foreach ( var row in asyncWriteAdapter ! . GetRowsAsync ( props , cancellationToken ) . ConfigureAwait ( false ) )
330326 {
331- await WriteCellAsync( writer , currentRowIndex , cellValue . CellIndex , cellValue . Value , cellValue . Prop , widths ) . ConfigureAwait ( false ) ;
332- progress? . Report ( 1 ) ;
327+ cancellationToken. ThrowIfCancellationRequested ( ) ;
328+ await writer. WriteAsync ( WorksheetXml . StartRow ( ++ currentRowIndex ) , cancellationToken ) . ConfigureAwait ( false ) ;
329+
330+ await foreach ( var cellValue in row. ConfigureAwait ( false ) . WithCancellation ( cancellationToken ) )
331+ {
332+ await WriteCellAsync( writer , currentRowIndex , cellValue . CellIndex , cellValue . Value , cellValue . Prop , widths ) . ConfigureAwait ( false ) ;
333+ progress? . Report ( 1 ) ;
334+ }
335+ await writer. WriteAsync ( WorksheetXml . EndRow , cancellationToken ) . ConfigureAwait ( false ) ;
333336 }
334- await writer. WriteAsync ( WorksheetXml . EndRow , cancellationToken ) . ConfigureAwait ( false ) ;
335- }
336337#endif
337- }
338- maxRowIndex = currentRowIndex;
338+ }
339+ maxRowIndex = currentRowIndex;
339340
340- await writer. WriteAsync ( WorksheetXml . EndSheetData , cancellationToken ) . ConfigureAwait ( false ) ;
341+ await writer. WriteAsync ( WorksheetXml . EndSheetData , cancellationToken ) . ConfigureAwait ( false ) ;
341342
342- if ( _configuration . AutoFilter )
343- {
344- await writer. WriteAsync ( WorksheetXml . Autofilter ( GetDimensionRef ( maxRowIndex , maxColumnIndex ) ) , cancellationToken ) . ConfigureAwait ( false ) ;
345- }
343+ if ( _configuration . AutoFilter )
344+ {
345+ await writer. WriteAsync ( WorksheetXml . Autofilter ( GetDimensionRef ( maxRowIndex , maxColumnIndex ) ) , cancellationToken ) . ConfigureAwait ( false ) ;
346+ }
346347
347- await writer. WriteAsync ( WorksheetXml . Drawing ( _currentSheetIndex ) , cancellationToken ) . ConfigureAwait ( false ) ;
348- await writer. WriteAsync ( WorksheetXml . EndWorksheet , cancellationToken ) . ConfigureAwait ( false ) ;
348+ await writer. WriteAsync ( WorksheetXml . Drawing ( _currentSheetIndex ) , cancellationToken ) . ConfigureAwait ( false ) ;
349+ await writer. WriteAsync ( WorksheetXml . EndWorksheet , cancellationToken ) . ConfigureAwait ( false ) ;
349350
350- if ( _configuration . FastMode && dimensionPlaceholderPostition != 0 )
351- {
352- await WriteDimensionAsync( writer , maxRowIndex , maxColumnIndex , dimensionPlaceholderPostition ) . ConfigureAwait ( false ) ;
351+ if ( _configuration . FastMode && dimensionPlaceholderPostition != 0 )
352+ {
353+ await WriteDimensionAsync( writer , maxRowIndex , maxColumnIndex , dimensionPlaceholderPostition ) . ConfigureAwait ( false ) ;
354+ }
355+ if ( _configuration . EnableAutoWidth )
356+ {
357+ await OverwriteColumnWidthPlaceholdersAsync( writer , columnWidthsPlaceholderPosition , widths ? . Columns , cancellationToken ) . ConfigureAwait ( false ) ;
358+ }
359+
360+ if ( _printHeader )
361+ maxRowIndex-- ;
362+
363+ return maxRowIndex;
353364 }
354- if ( _configuration . EnableAutoWidth )
365+ finally
355366 {
356- await OverwriteColumnWidthPlaceholdersAsync( writer , columnWidthsPlaceholderPosition , widths ? . Columns , cancellationToken ) . ConfigureAwait ( false ) ;
367+ #if ! SYNC_ONLY
368+ if ( asyncWriteAdapter is IAsyncDisposable asyncDisposable )
369+ {
370+ await asyncDisposable. DisposeAsync ( ) . ConfigureAwait ( false ) ;
371+ }
372+ #endif
357373 }
358-
359- if ( _printHeader )
360- maxRowIndex-- ;
361-
362- return maxRowIndex;
363374 }
364375
365376 [ CreateSyncVersion ]
@@ -390,7 +401,7 @@ private static async Task OverwriteColumnWidthPlaceholdersAsync(SafeStreamWriter
390401 private static async Task WriteColumnsWidthsAsync( SafeStreamWriter writer , IEnumerable < ExcelColumnWidth > ? columnWidths , CancellationToken cancellationToken = default )
391402 {
392403 var hasWrittenStart = false;
393-
404+
394405 columnWidths ??= [ ] ;
395406 foreach ( var column in columnWidths )
396407 {
@@ -610,9 +621,9 @@ private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToke
610621#if NET5_0_OR_GREATER
611622#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
612623#if NET10_0_OR_GREATER
613- await using var stream = await contentTypesZipEntry. OpenAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
624+ await using var stream = await contentTypesZipEntry. OpenAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
614625#else
615- await using var stream = contentTypesZipEntry. Open ( ) ;
626+ await using var stream = contentTypesZipEntry. Open ( ) ;
616627#endif
617628#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
618629#else
0 commit comments