From fb4e06623796f3e1eb5c3063fe2271246ef58994 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Tue, 10 Jun 2025 11:14:03 -0400 Subject: [PATCH 01/25] Implement real async instead of Task.Run wrappers --- src/MiniExcel/Csv/CsvReader.cs | 75 +++++++---------- src/MiniExcel/IExcelReader.cs | 8 +- src/MiniExcel/MiniExcel.Async.cs | 4 +- src/MiniExcel/MiniExcelLibs.csproj | 14 +++- src/MiniExcel/MiniExcelTask.cs | 10 +-- .../OpenXml/ExcelOpenXmlSheetReader.Async.cs | 39 --------- .../OpenXml/ExcelOpenXmlSheetReader.cs | 81 ++++++++++++------- src/MiniExcel/Utils/ImageHelper.cs | 2 +- src/MiniExcel/Utils/StringHelper.cs | 34 +++++--- src/MiniExcel/Utils/XmlReaderHelper.cs | 67 +++++++++++---- .../MiniExcelIssueAsyncTests.cs | 4 +- tests/MiniExcelTests/MiniExcelIssueTests.cs | 2 +- .../MiniExcelOpenXmlAsyncTests.cs | 8 +- 13 files changed, 183 insertions(+), 165 deletions(-) delete mode 100644 src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.Async.cs diff --git a/src/MiniExcel/Csv/CsvReader.cs b/src/MiniExcel/Csv/CsvReader.cs index 39562333..289420fc 100644 --- a/src/MiniExcel/Csv/CsvReader.cs +++ b/src/MiniExcel/Csv/CsvReader.cs @@ -8,10 +8,11 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using System.Runtime.CompilerServices; namespace MiniExcelLibs.Csv { - internal class CsvReader : IExcelReader + internal partial class CsvReader : IExcelReader { private Stream _stream; private CsvConfiguration _config; @@ -22,7 +23,8 @@ public CsvReader(Stream stream, IConfiguration configuration) _config = configuration == null ? CsvConfiguration.DefaultConfiguration : (CsvConfiguration)configuration; } - public IEnumerable> Query(bool useHeaderRow, string sheetName, string startCell) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, [EnumeratorCancellation] CancellationToken ct = default) { if (startCell != "A1") throw new NotImplementedException("CSV does not implement parameter startCell"); @@ -35,14 +37,22 @@ public IEnumerable> Query(bool useHeaderRow, string var headRows = new Dictionary(); string row; - for (var rowIndex = 1; (row = reader.ReadLine()) != null; rowIndex++) + for (var rowIndex = 1; (row = await reader.ReadLineAsync( +#if NET7_0_OR_GREATER +ct +#endif + )) != null; rowIndex++) { string finalRow = row; if (_config.ReadLineBreaksWithinQuotes) { while (finalRow.Count(c => c == '"') % 2 != 0) { - var nextPart = reader.ReadLine(); + var nextPart = await reader.ReadLineAsync( +#if NET7_0_OR_GREATER +ct +#endif + ); if (nextPart == null) { break; @@ -107,62 +117,37 @@ public IEnumerable> Query(bool useHeaderRow, string } } - public IEnumerable Query(string sheetName, string startCell, bool hasHeader) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken ct = default) where T : class, new() { - var dynamicRecords = Query(false, sheetName, startCell); - return ExcelOpenXmlSheetReader.QueryImpl(dynamicRecords, startCell, hasHeader, _config); + var dynamicRecords = QueryAsync(false, sheetName, startCell, ct); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, _config, ct); } - public IEnumerable> QueryRange(bool useHeaderRow, string sheetName, string startCell, string endCell) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken ct = default) { throw new NotImplementedException("CSV does not implement QueryRange"); } - public IEnumerable QueryRange(string sheetName, string startCell, string endCell, bool hasHeader) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken ct = default) where T : class, new() { - var dynamicRecords = QueryRange(false, sheetName, startCell, endCell); - return ExcelOpenXmlSheetReader.QueryImpl(dynamicRecords, startCell, hasHeader, this._config); + var dynamicRecords = QueryRangeAsync(false, sheetName, startCell, endCell, ct); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, this._config, ct); } - public IEnumerable> QueryRange(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken ct = default) { throw new NotImplementedException("CSV does not implement QueryRange"); } - public IEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken ct = default) where T : class, new() { - var dynamicRecords = QueryRange(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex); - return ExcelOpenXmlSheetReader.QueryImpl(dynamicRecords, ReferenceHelper.ConvertXyToCell(startRowIndex, startColumnIndex), hasHeader, this._config); - } - - public Task>> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default) - { - return Task.Run(() => Query(useHeaderRow, sheetName, startCell), cancellationToken); - } - - public async Task> QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() - { - return await Task.Run(() => Query(sheetName, startCell, hasHeader), cancellationToken).ConfigureAwait(false); - } - - public Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCel, CancellationToken cancellationToken = default) - { - return Task.Run(() => QueryRange(useHeaderRow, sheetName, startCell, endCel), cancellationToken); - } - - public async Task> QueryRangeAsync(string sheetName, string startCell, string endCel, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() - { - return await Task.Run(() => QueryRange(sheetName, startCell, endCel, hasHeader), cancellationToken).ConfigureAwait(false); - } - - public Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default) - { - return Task.Run(() => QueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex), cancellationToken); - } - - public async Task> QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() - { - return await Task.Run(() => QueryRange(sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, hasHeader), cancellationToken).ConfigureAwait(false); + var dynamicRecords = QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, ReferenceHelper.ConvertXyToCell(startRowIndex, startColumnIndex), hasHeader, this._config, ct); } private string[] Split(string row) diff --git a/src/MiniExcel/IExcelReader.cs b/src/MiniExcel/IExcelReader.cs index 0581cd34..5fcd541e 100644 --- a/src/MiniExcel/IExcelReader.cs +++ b/src/MiniExcel/IExcelReader.cs @@ -9,15 +9,11 @@ internal interface IExcelReader : IDisposable { IEnumerable> Query(bool useHeaderRow, string sheetName, string startCell); IEnumerable Query(string sheetName, string startCell, bool hasHeader) where T : class, new(); - Task>> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default); - Task> QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new(); + IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default); + IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new(); IEnumerable> QueryRange(bool useHeaderRow, string sheetName, string startCell, string endCell); IEnumerable QueryRange(string sheetName, string startCell, string endCell, bool hasHeader) where T : class, new(); - Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default); - Task> QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new(); IEnumerable> QueryRange(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex); IEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader) where T : class, new(); - Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default); - Task> QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new(); } } diff --git a/src/MiniExcel/MiniExcel.Async.cs b/src/MiniExcel/MiniExcel.Async.cs index 51ede3f3..7877ced6 100644 --- a/src/MiniExcel/MiniExcel.Async.cs +++ b/src/MiniExcel/MiniExcel.Async.cs @@ -86,9 +86,9 @@ public static async Task> QueryAsync(string path, bool useH return await Task.Run(() => Query(path, useHeaderRow, sheetName, excelType, startCell, configuration), cancellationToken); } - public static async Task> QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default, bool hasHeader = true) where T : class, new() + public static IAsyncEnumerable QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, CancellationToken cancellationToken = default) where T : class, new() { - return await ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).QueryAsync(sheetName, startCell, hasHeader, cancellationToken).ConfigureAwait(false); + return ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).QueryAsync(sheetName, startCell, hasHeader, cancellationToken); } public static async Task> QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default, bool hasHeader = true) where T : class, new() diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj index eb4a83c6..36afb04f 100644 --- a/src/MiniExcel/MiniExcelLibs.csproj +++ b/src/MiniExcel/MiniExcelLibs.csproj @@ -1,9 +1,9 @@  - net45;netstandard2.0;net8.0;net9.0 + net462;netstandard2.0;net8.0;net9.0 1.41.2 - + 8 @@ -38,7 +38,7 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=trueREADME.md - + @@ -52,7 +52,13 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/src/MiniExcel/MiniExcelTask.cs b/src/MiniExcel/MiniExcelTask.cs index 06f8d414..2a3fb7b0 100644 --- a/src/MiniExcel/MiniExcelTask.cs +++ b/src/MiniExcel/MiniExcelTask.cs @@ -6,7 +6,7 @@ namespace MiniExcelLibs { internal class MiniExcelTask { -#if NET45 +#if NET462 public static Task CompletedTask = Task.FromResult(0); #else public static Task CompletedTask = Task.CompletedTask; @@ -14,7 +14,7 @@ internal class MiniExcelTask public static Task FromException(Exception exception) { -#if NET45 +#if NET462 var tcs = new TaskCompletionSource(); tcs.SetException(exception); return tcs.Task; @@ -25,7 +25,7 @@ public static Task FromException(Exception exception) public static Task FromException(Exception exception) { -#if NET45 +#if NET462 var tcs = new TaskCompletionSource(); tcs.SetException(exception); return tcs.Task; @@ -36,7 +36,7 @@ public static Task FromException(Exception exception) public static Task FromCanceled(CancellationToken cancellationToken) { -#if NET45 +#if NET462 var tcs = new TaskCompletionSource(); cancellationToken.Register(() => tcs.SetCanceled()); return tcs.Task; @@ -47,7 +47,7 @@ public static Task FromCanceled(CancellationToken cancellationToken) public static Task FromCanceled(CancellationToken cancellationToken) { -#if NET45 +#if NET462 var tcs = new TaskCompletionSource(); cancellationToken.Register(() => tcs.SetCanceled()); return tcs.Task; diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.Async.cs deleted file mode 100644 index 2ad5ff99..00000000 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.Async.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace MiniExcelLibs.OpenXml -{ - internal partial class ExcelOpenXmlSheetReader : IExcelReader - { - public async Task>> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default) - { - return await Task.Run(() => Query(useHeaderRow, sheetName, startCell), cancellationToken).ConfigureAwait(false); - } - - public async Task> QueryAsync(string sheetName, string startCell, bool hasHeader = true, CancellationToken cancellationToken = default) where T : class, new() - { - return await Task.Run(() => Query(sheetName, startCell, hasHeader), cancellationToken).ConfigureAwait(false); - } - - public async Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default) - { - return await Task.Run(() => Query(useHeaderRow, sheetName, startCell), cancellationToken).ConfigureAwait(false); - } - - public async Task> QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader = true, CancellationToken cancellationToken = default) where T : class, new() - { - return await Task.Run(() => QueryRange(sheetName, startCell, endCell, hasHeader), cancellationToken).ConfigureAwait(false); - } - - public async Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default) - { - return await Task.Run(() => QueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex), cancellationToken).ConfigureAwait(false); - } - - public async Task> QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader = true, CancellationToken cancellationToken = default) where T : class, new() - { - return await Task.Run(() => QueryRange(sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, hasHeader), cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs index b5a21a07..539f34b3 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs @@ -8,6 +8,7 @@ using System.IO; using System.IO.Compression; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using System.Xml; @@ -26,12 +27,7 @@ internal partial class ExcelOpenXmlSheetReader : IExcelReader internal readonly ExcelOpenXmlZip _archive; private readonly OpenXmlConfiguration _config; - private static readonly XmlReaderSettings _xmlSettings = new XmlReaderSettings - { - IgnoreComments = true, - IgnoreWhitespace = true, - XmlResolver = null - }; + private static readonly XmlReaderSettings _xmlSettings = GetXmlReaderSettings(false); public ExcelOpenXmlSheetReader(Stream stream, IConfiguration configuration, bool isUpdateMode = true) { @@ -40,22 +36,25 @@ public ExcelOpenXmlSheetReader(Stream stream, IConfiguration configuration, bool SetSharedStrings(); } - public IEnumerable> Query(bool useHeaderRow, string sheetName, string startCell) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken ct = default) { - return QueryRange(useHeaderRow, sheetName, startCell, ""); + return QueryRangeAsync(useHeaderRow, sheetName, startCell, "", ct); } - public IEnumerable Query(string sheetName, string startCell, bool hasHeader) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken ct = default) where T : class, new() { if (sheetName == null) sheetName = CustomPropertyHelper.GetExcellSheetInfo(typeof(T), _config)?.ExcelSheetName; //Todo: Find a way if possible to remove the 'hasHeader' parameter to check whether or not to include // the first row in the result set in favor of modifying the already present 'useHeaderRow' to do the same job - return QueryImpl(Query(false, sheetName, startCell), startCell, hasHeader, _config); + return QueryImplAsync(QueryAsync(false, sheetName, startCell, ct), startCell, hasHeader, _config); } - public IEnumerable> QueryRange(bool useHeaderRow, string sheetName, string startCell, string endCell) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken ct = default) { if (!ReferenceHelper.ParseReference(startCell, out var startColumnIndex, out var startRowIndex)) { @@ -80,15 +79,17 @@ public IEnumerable> QueryRange(bool useHeaderRow, st endRowIndex = rIndex - 1; } - return InternalQueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex); + return InternalQueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct); } - public IEnumerable QueryRange(string sheetName, string startCell, string endCell, bool hasHeader) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken ct = default) where T : class, new() { - return QueryImpl(QueryRange(false, sheetName, startCell, endCell), startCell, hasHeader, this._config); + return QueryImplAsync(QueryRangeAsync(false, sheetName, startCell, endCell, ct), startCell, hasHeader, this._config); } - public IEnumerable> QueryRange(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken ct = default) { if (startRowIndex <= 0) { @@ -121,16 +122,26 @@ public IEnumerable> QueryRange(bool useHeaderRow, st endColumnIndex--; } - return InternalQueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex); + return InternalQueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct); } - public IEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken ct = default) where T : class, new() { - return QueryImpl(QueryRange(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config); + return QueryImplAsync(QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config); } - internal IEnumerable> InternalQueryRange(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal async IAsyncEnumerable> InternalQueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, [EnumeratorCancellation] CancellationToken ct = default) { + var xmlSettings = GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + var sheetEntry = GetSheetEntry(sheetName); // TODO: need to optimize performance @@ -152,19 +163,19 @@ internal IEnumerable> InternalQueryRange(bool useHea } using (var sheetStream = sheetEntry.Open()) - using (var reader = XmlReader.Create(sheetStream, _xmlSettings)) + using (var reader = XmlReader.Create(sheetStream, xmlSettings)) { if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) yield break; - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) yield break; while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) continue; var headRows = new Dictionary(); @@ -182,8 +193,8 @@ internal IEnumerable> InternalQueryRange(bool useHea if (rowIndex < startRowIndex) { - XmlReaderHelper.ReadFirstContent(reader); - XmlReaderHelper.SkipToNextSameLevelDom(reader); + await XmlReaderHelper.ReadFirstContentAsync(reader, ct); + await XmlReaderHelper.SkipToNextSameLevelDomAsync(reader, ct); continue; } if (endRowIndex.HasValue && rowIndex > endRowIndex.Value) @@ -205,7 +216,7 @@ internal IEnumerable> InternalQueryRange(bool useHea } // row -> c, must after `if (nextRowIndex < rowIndex)` condition code, eg. The first empty row has no xml element,and the second row xml element is - if (!XmlReaderHelper.ReadFirstContent(reader) && !_config.IgnoreEmptyRows) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct) && !_config.IgnoreEmptyRows) { //Fill in case of self closed empty row tag eg. yield return GetCell(useHeaderRow, maxColumnIndex, headRows, startColumnIndex); @@ -272,13 +283,13 @@ internal IEnumerable> InternalQueryRange(bool useHea yield return cell; } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) { break; } } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) { break; } @@ -286,7 +297,8 @@ internal IEnumerable> InternalQueryRange(bool useHea } } - public static IEnumerable QueryImpl(IEnumerable> values, string startCell, bool hasHeader, Configuration configuration) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryImplAsync(IAsyncEnumerable> values, string startCell, bool hasHeader, Configuration configuration, [EnumeratorCancellation] CancellationToken ct = default) where T : class, new() { var type = typeof(T); @@ -297,7 +309,7 @@ internal IEnumerable> InternalQueryRange(bool useHea var first = true; var rowIndex = 0; - foreach (var item in values) + await foreach (var item in values.WithCancellation(ct).ConfigureAwait(false)) { if (first) { @@ -417,6 +429,17 @@ private static void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, } } + private static XmlReaderSettings GetXmlReaderSettings(bool async) + { + return new XmlReaderSettings + { + IgnoreComments = true, + IgnoreWhitespace = true, + XmlResolver = null, + Async = async, + }; + } + private void SetSharedStrings() { if (_sharedStrings != null) diff --git a/src/MiniExcel/Utils/ImageHelper.cs b/src/MiniExcel/Utils/ImageHelper.cs index cd568ee9..2137c6b3 100644 --- a/src/MiniExcel/Utils/ImageHelper.cs +++ b/src/MiniExcel/Utils/ImageHelper.cs @@ -14,7 +14,7 @@ public enum ImageFormat unknown } -#if NET45||NETSTANDARD2_0 +#if NET462||NETSTANDARD2_0 public static ImageFormat GetImageFormat(byte[] bytes) { var bmp = new byte[] { (byte)'B', (byte)'M' }; // BMP diff --git a/src/MiniExcel/Utils/StringHelper.cs b/src/MiniExcel/Utils/StringHelper.cs index e6093db4..d8d2d6c5 100644 --- a/src/MiniExcel/Utils/StringHelper.cs +++ b/src/MiniExcel/Utils/StringHelper.cs @@ -2,11 +2,13 @@ using System; using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; using System.Xml; - + namespace MiniExcelLibs.Utils { - internal static class StringHelper + internal static partial class StringHelper { private static readonly string[] _ns = { Config.SpreadsheetmlXmlns, Config.SpreadsheetmlXmlStrictns }; @@ -16,10 +18,11 @@ internal static class StringHelper /// /// Copied and modified from ExcelDataReader - @MIT License /// - public static string ReadStringItem(XmlReader reader) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ReadStringItemAsync(XmlReader reader, CancellationToken ct = default) { var result = new StringBuilder(); - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) return string.Empty; while (!reader.EOF) @@ -27,13 +30,17 @@ public static string ReadStringItem(XmlReader reader) if (XmlReaderHelper.IsStartElement(reader, "t", _ns)) { // There are multiple in a . Concatenate within an . - result.Append(reader.ReadElementContentAsString()); + result.Append(await reader.ReadElementContentAsStringAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif + ); } else if (XmlReaderHelper.IsStartElement(reader, "r", _ns)) { - result.Append(ReadRichTextRun(reader)); + result.Append(await ReadRichTextRunAsync(reader, ct)); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) { break; } @@ -45,19 +52,24 @@ public static string ReadStringItem(XmlReader reader) /// /// Copied and modified from ExcelDataReader - @MIT License /// - private static string ReadRichTextRun(XmlReader reader) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private static async Task ReadRichTextRunAsync(XmlReader reader, CancellationToken ct = default) { var result = new StringBuilder(); - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) return string.Empty; while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "t", _ns)) { - result.Append(reader.ReadElementContentAsString()); + result.Append(await reader.ReadElementContentAsStringAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif +); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) { break; } diff --git a/src/MiniExcel/Utils/XmlReaderHelper.cs b/src/MiniExcel/Utils/XmlReaderHelper.cs index 67462049..357f0678 100644 --- a/src/MiniExcel/Utils/XmlReaderHelper.cs +++ b/src/MiniExcel/Utils/XmlReaderHelper.cs @@ -1,59 +1,93 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using System.Xml; namespace MiniExcelLibs.Utils { - internal static class XmlReaderHelper + internal static partial class XmlReaderHelper { /// /// Pass <?xml> and <worksheet> /// /// - public static void PassXmlDeclarationAndWorksheet(this XmlReader reader) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task PassXmlDeclarationAndWorksheet(this XmlReader reader, CancellationToken ct = default) { - reader.MoveToContent(); - reader.Read(); + await reader.MoveToContentAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif +; + await reader.ReadAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif +; } /// /// e.g skip row 1 to row 2 /// /// - public static void SkipToNextSameLevelDom(XmlReader reader) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SkipToNextSameLevelDomAsync(XmlReader reader, CancellationToken ct = default) { while (!reader.EOF) { - if (!SkipContent(reader)) + if (!await SkipContentAsync(reader, ct)) break; } } //Method from ExcelDataReader @MIT License - public static bool ReadFirstContent(XmlReader reader) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ReadFirstContentAsync(XmlReader reader, CancellationToken ct = default) { if (reader.IsEmptyElement) { - reader.Read(); + await reader.ReadAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif +; return false; } - reader.MoveToContent(); - reader.Read(); + await reader.MoveToContentAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif + ; + await reader.ReadAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif + ; return true; } //Method from ExcelDataReader @MIT License - public static bool SkipContent(XmlReader reader) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SkipContentAsync(XmlReader reader, CancellationToken ct = default) { if (reader.NodeType == XmlNodeType.EndElement) { - reader.Read(); + await reader.ReadAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif +; return false; } - reader.Skip(); + await reader.SkipAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif + ; return true; } @@ -69,14 +103,15 @@ public static string GetAttribute(XmlReader reader, string name, params string[] .FirstOrDefault(at => at != null); } - public static IEnumerable GetSharedStrings(Stream stream, params string[] nss) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream, CancellationToken ct = default, params string[] nss) { using (var reader = XmlReader.Create(stream)) { if (!IsStartElement(reader, "sst", nss)) yield break; - if (!ReadFirstContent(reader)) + if (!await ReadFirstContentAsync(reader, ct)) yield break; while (!reader.EOF) @@ -86,7 +121,7 @@ public static IEnumerable GetSharedStrings(Stream stream, params string[ var value = StringHelper.ReadStringItem(reader); yield return value; } - else if (!SkipContent(reader)) + else if (!await SkipContentAsync(reader, ct)) { break; } diff --git a/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs b/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs index 62b41a9e..e8c34f73 100644 --- a/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs @@ -638,7 +638,7 @@ public async Task Issue227() } { await using var stream = File.OpenRead(path); - var q = await stream.QueryAsync(); + var q = stream.QueryAsync().ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(100, rows.Count); @@ -942,7 +942,7 @@ public async Task Issue89() await writer.FlushAsync(); stream.Position = 0; - var q = await stream.QueryAsync(excelType: ExcelType.CSV); + var q = stream.QueryAsync(excelType: ExcelType.CSV).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(Issue89VO.WorkState.OnDuty, rows[0].State); diff --git a/tests/MiniExcelTests/MiniExcelIssueTests.cs b/tests/MiniExcelTests/MiniExcelIssueTests.cs index 11221ad6..a957c675 100644 --- a/tests/MiniExcelTests/MiniExcelIssueTests.cs +++ b/tests/MiniExcelTests/MiniExcelIssueTests.cs @@ -4066,7 +4066,7 @@ static IEnumerable GetTestData() memoryStream.Position = 0; - var queryData = (await memoryStream.QueryAsync()).ToList(); + var queryData = (memoryStream.QueryAsync()).ToBlockingEnumerable().ToList(); Assert.Equal(testData.Count(), queryData.Count); diff --git a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs index df42e3f5..d477a28d 100644 --- a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs @@ -319,8 +319,8 @@ public async Task QueryStrongTypeMapping_Test() const string path = "../../../../../samples/xlsx/TestTypeMapping.xlsx"; await using (var stream = File.OpenRead(path)) { - var d = await stream.QueryAsync(); - var rows = d.ToList(); + var d = stream.QueryAsync(); + var rows = d.ToBlockingEnumerable().ToList(); Assert.Equal(100, rows.Count); Assert.Equal(Guid.Parse("78DE23D2-DCB6-BD3D-EC67-C112BBC322A2"), rows[0].ID); @@ -360,7 +360,7 @@ public async Task AutoCheckTypeTest() { const string path = "../../../../../samples/xlsx/TestTypeMapping_AutoCheckFormat.xlsx"; await using var stream = FileHelper.OpenRead(path); - _ = (await stream.QueryAsync()).ToList(); + _ = stream.QueryAsync().ToBlockingEnumerable().ToList(); } [Fact] @@ -384,7 +384,7 @@ public async Task LargeFileQueryStrongTypeMapping_Test() const string path = "../../../../../benchmarks/MiniExcel.Benchmarks/Test1,000,000x10.xlsx"; await using (var stream = File.OpenRead(path)) { - var d = await stream.QueryAsync(); + var d = stream.QueryAsync().ToBlockingEnumerable(); var rows = d.Take(2).ToList(); Assert.Equal("HelloWorld2", rows[0].HelloWorld1); Assert.Equal("HelloWorld3", rows[1].HelloWorld1); From fe8a036a2330da1dbeba2a262aced5f5dfa2a918 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Thu, 12 Jun 2025 08:41:51 -0400 Subject: [PATCH 02/25] Use CreateSyncVersion in interface --- src/MiniExcel/Csv/CsvReader.cs | 2 +- src/MiniExcel/IExcelReader.cs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/MiniExcel/Csv/CsvReader.cs b/src/MiniExcel/Csv/CsvReader.cs index 289420fc..e0dae53f 100644 --- a/src/MiniExcel/Csv/CsvReader.cs +++ b/src/MiniExcel/Csv/CsvReader.cs @@ -144,7 +144,7 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken ct = default) where T : class, new() + public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken ct = default) where T : class, new() { var dynamicRecords = QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct); return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, ReferenceHelper.ConvertXyToCell(startRowIndex, startColumnIndex), hasHeader, this._config, ct); diff --git a/src/MiniExcel/IExcelReader.cs b/src/MiniExcel/IExcelReader.cs index 5fcd541e..eb8e2010 100644 --- a/src/MiniExcel/IExcelReader.cs +++ b/src/MiniExcel/IExcelReader.cs @@ -1,19 +1,22 @@ using System; using System.Collections.Generic; using System.Threading; -using System.Threading.Tasks; namespace MiniExcelLibs { - internal interface IExcelReader : IDisposable + internal partial interface IExcelReader : IDisposable { - IEnumerable> Query(bool useHeaderRow, string sheetName, string startCell); - IEnumerable Query(string sheetName, string startCell, bool hasHeader) where T : class, new(); + [Zomp.SyncMethodGenerator.CreateSyncVersion] IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default); + [Zomp.SyncMethodGenerator.CreateSyncVersion] IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new(); - IEnumerable> QueryRange(bool useHeaderRow, string sheetName, string startCell, string endCell); - IEnumerable QueryRange(string sheetName, string startCell, string endCell, bool hasHeader) where T : class, new(); - IEnumerable> QueryRange(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex); - IEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader) where T : class, new(); + [Zomp.SyncMethodGenerator.CreateSyncVersion] + IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default); + [Zomp.SyncMethodGenerator.CreateSyncVersion] + IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new(); + [Zomp.SyncMethodGenerator.CreateSyncVersion] + IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default); + [Zomp.SyncMethodGenerator.CreateSyncVersion] + IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new(); } } From 3f25658eaeb6d3823de36f10a10c9e6132608b35 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Thu, 12 Jun 2025 12:27:32 -0400 Subject: [PATCH 03/25] Fix Async tests --- src/MiniExcel/MiniExcel.Async.cs | 38 ---- src/MiniExcel/MiniExcel.cs | 23 ++- tests/MiniExcelTests/MiniExcelCsvAsycTests.cs | 8 +- .../MiniExcelIssueAsyncTests.cs | 114 +++++------ tests/MiniExcelTests/MiniExcelIssueTests.cs | 8 +- .../MiniExcelOpenXmlAsyncTests.cs | 184 +++++++++--------- ...MiniExcelOpenXmlMultipleSheetAsyncTests.cs | 26 +-- .../MiniExcelTemplateAsyncTests.cs | 28 +-- 8 files changed, 199 insertions(+), 230 deletions(-) diff --git a/src/MiniExcel/MiniExcel.Async.cs b/src/MiniExcel/MiniExcel.Async.cs index 7877ced6..a844a170 100644 --- a/src/MiniExcel/MiniExcel.Async.cs +++ b/src/MiniExcel/MiniExcel.Async.cs @@ -81,44 +81,6 @@ public static async Task MergeSameCellsAsync(this Stream stream, byte[] fileByte await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(fileBytes, cancellationToken); } - public static async Task> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - return await Task.Run(() => Query(path, useHeaderRow, sheetName, excelType, startCell, configuration), cancellationToken); - } - - public static IAsyncEnumerable QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, CancellationToken cancellationToken = default) where T : class, new() - { - return ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).QueryAsync(sheetName, startCell, hasHeader, cancellationToken); - } - - public static async Task> QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default, bool hasHeader = true) where T : class, new() - { - return await Task.Run(() => Query(path, sheetName, excelType, startCell, configuration, hasHeader), cancellationToken).ConfigureAwait(false); - } - - public static async Task> QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - var tcs = new TaskCompletionSource>(); - cancellationToken.Register(() => - { - tcs.TrySetCanceled(); - }); - - await Task.Run(() => - { - try - { - tcs.TrySetResult(Query(stream, useHeaderRow, sheetName, excelType, startCell, configuration)); - } - catch (Exception ex) - { - tcs.TrySetException(ex); - } - }, cancellationToken); - - return await tcs.Task; - - } public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) { await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, cancellationToken).ConfigureAwait(false); diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index 03470dbd..71a73856 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -10,6 +10,9 @@ using System.Dynamic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; namespace MiniExcelLibs { @@ -89,31 +92,35 @@ public static int[] SaveAs(this Stream stream, object value, bool printHeader = return ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAs(); } - public static IEnumerable Query(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken ct = default) where T : class, new() { using (var stream = FileHelper.OpenSharedRead(path)) - foreach (var item in Query(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, hasHeader)) + await foreach (var item in QueryAsync(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, hasHeader, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; //Foreach yield return twice reason : https://stackoverflow.com/questions/66791982/ienumerable-extract-code-lazy-loading-show-stream-was-not-readable } - public static IEnumerable Query(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken ct = default) where T : class, new() { using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) - foreach (var item in excelReader.Query(sheetName, startCell, hasHeader)) + await foreach (var item in excelReader.QueryAsync(sheetName, startCell, hasHeader, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; } - public static IEnumerable Query(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - foreach (var item in Query(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration)) + await foreach (var item in QueryAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; } - public static IEnumerable Query(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) - foreach (var item in excelReader.Query(useHeaderRow, sheetName, startCell)) + await foreach (var item in excelReader.QueryAsync(useHeaderRow, sheetName, startCell, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } diff --git a/tests/MiniExcelTests/MiniExcelCsvAsycTests.cs b/tests/MiniExcelTests/MiniExcelCsvAsycTests.cs index 46dd2c55..79aff1b2 100644 --- a/tests/MiniExcelTests/MiniExcelCsvAsycTests.cs +++ b/tests/MiniExcelTests/MiniExcelCsvAsycTests.cs @@ -18,7 +18,7 @@ public async Task Gb2312_Encoding_Read_Test() { StreamReaderFunc = stream => new StreamReader(stream, encoding: Encoding.GetEncoding("gb2312")) }; - var q = await MiniExcel.QueryAsync(path, true, excelType: ExcelType.CSV, configuration: config); + var q = MiniExcel.QueryAsync(path, true, excelType: ExcelType.CSV, configuration: config).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("世界你好", rows[0].栏位1); } @@ -227,7 +227,7 @@ public async Task CsvExcelTypeTest() Assert.Equal("A,B", texts[0]); Assert.Equal("Test1,Test2", texts[1]); - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows1 = q.ToList(); Assert.Equal("A", rows1[0].A); @@ -257,7 +257,7 @@ await MiniExcel.SaveAsAsync(path, new[] await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: true, excelType: ExcelType.CSV)).ToList(); + var rows = stream.QueryAsync(useHeaderRow: true, excelType: ExcelType.CSV).ToBlockingEnumerable().ToList(); Assert.Equal("A1", rows[0].c1); Assert.Equal("B1", rows[0].c2); Assert.Equal("A2", rows[1].c1); @@ -265,7 +265,7 @@ await MiniExcel.SaveAsAsync(path, new[] } { - var rows = (await MiniExcel.QueryAsync(path, useHeaderRow: true, excelType: ExcelType.CSV)).ToList(); + var rows = MiniExcel.QueryAsync(path, useHeaderRow: true, excelType: ExcelType.CSV).ToBlockingEnumerable().ToList(); Assert.Equal("A1", rows[0].c1); Assert.Equal("B1", rows[0].c2); Assert.Equal("A2", rows[1].c1); diff --git a/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs b/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs index e8c34f73..1fcb1596 100644 --- a/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelIssueAsyncTests.cs @@ -38,7 +38,7 @@ public async Task Issue255() }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var q = await MiniExcel.QueryAsync(path.ToString()); + var q = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("2021", rows[1].A.ToString()); @@ -59,7 +59,7 @@ public async Task Issue255() Assert.Single(rowsWritten); Assert.Equal(1, rowsWritten[0]); - var q = await MiniExcel.QueryAsync(path.ToString()); + var q = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("2021", rows[1].A.ToString()); Assert.Equal("2021", rows[1].B.ToString()); @@ -83,7 +83,7 @@ private class Issue255DTO public async Task Issue256() { var path = PathHelper.GetFile("xlsx/TestIssue256.xlsx"); - var q = await MiniExcel.QueryAsync(path, false); + var q = MiniExcel.QueryAsync(path, false).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(new DateTime(2003, 4, 16), rows[1].A); @@ -183,10 +183,10 @@ public async Task Issue251() public async Task Issue242() { var path = PathHelper.GetFile("xls/TestIssue242.xls"); - await Assert.ThrowsAsync(async () => _ = (await MiniExcel.QueryAsync(path)).ToList()); + Assert.Throws(() => _ = MiniExcel.QueryAsync(path).ToBlockingEnumerable().ToList()); await using var stream = File.OpenRead(path); - await Assert.ThrowsAsync(async () => _ = (await stream.QueryAsync()).ToList()); + Assert.Throws(() => _ = (stream.QueryAsync().ToBlockingEnumerable()).ToList()); } /// @@ -206,7 +206,7 @@ public async Task Issue243() Assert.Single(rowsWritten); Assert.Equal(2, rowsWritten[0]); - var q = await MiniExcel.QueryAsync(path.ToString()); + var q = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("Jack", rows[0].Name); @@ -247,7 +247,7 @@ public async Task Issue241() Assert.Equal(2, rowsWritten[0]); { - var q = await MiniExcel.QueryAsync(path, true); + var q = MiniExcel.QueryAsync(path, true).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(rows[0].InDate, "01 04, 2021"); @@ -255,7 +255,7 @@ public async Task Issue241() } { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(rows[0].InDate, new DateTime(2021, 01, 04)); @@ -273,7 +273,7 @@ public async Task Issue241() Assert.Equal(2, rowsWritten[0]); { - var q = await MiniExcel.QueryAsync(path, true); + var q = MiniExcel.QueryAsync(path, true).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(rows[0].InDate, "01 04, 2021"); @@ -281,7 +281,7 @@ public async Task Issue241() } { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(rows[0].InDate, new DateTime(2021, 01, 04)); @@ -375,7 +375,7 @@ public async Task Issue235() Assert.Equal("department", sheetNames[1]); { - var q = await MiniExcel.QueryAsync(path, true, sheetName: "users"); + var q = MiniExcel.QueryAsync(path, true, sheetName: "users").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("Jack", rows[0].Name); Assert.Equal(25, rows[0].Age); @@ -383,7 +383,7 @@ public async Task Issue235() Assert.Equal(44, rows[1].Age); } { - var q = await MiniExcel.QueryAsync(path, true, sheetName: "department"); + var q = MiniExcel.QueryAsync(path, true, sheetName: "department").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("01", rows[0].ID); Assert.Equal("HR", rows[0].Name); @@ -425,7 +425,7 @@ public async Task Issue237() }; await MiniExcel.SaveAsAsync(path.ToString(), value); - var q = await MiniExcel.QueryAsync(path.ToString(), true); + var q = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("\"\"1,2,3\"\"", rows[0].id); @@ -467,7 +467,7 @@ public async Task Issue234() Assert.Equal("department", sheetNames[1]); { - var q = await MiniExcel.QueryAsync(path, true, sheetName: "users"); + var q = MiniExcel.QueryAsync(path, true, sheetName: "users").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("Jack", rows[0].Name); @@ -476,7 +476,7 @@ public async Task Issue234() Assert.Equal(44, rows[1].Age); } { - var q = await MiniExcel.QueryAsync(path, true, sheetName: "department"); + var q = MiniExcel.QueryAsync(path, true, sheetName: "department").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("01", rows[0].ID); @@ -540,7 +540,7 @@ public async Task Issue230() Assert.Single(rowsWritten); Assert.Equal(2, rowsWritten[0]); - var q = await MiniExcel.QueryAsync(path.ToString(), true); + var q = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(1, rows[0].id); @@ -582,7 +582,7 @@ public async Task Issue122() { var path = PathHelper.GetFile("xlsx/TestIssue122.xlsx"); { - var q = await MiniExcel.QueryAsync(path, useHeaderRow: true, configuration: config); + var q = MiniExcel.QueryAsync(path, useHeaderRow: true, configuration: config).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("HR", rows[0].Department); Assert.Equal("HR", rows[1].Department); @@ -596,7 +596,7 @@ public async Task Issue122() { var path = PathHelper.GetFile("xlsx/TestIssue122_2.xlsx"); { - var q = await MiniExcel.QueryAsync(path, useHeaderRow: true, configuration: config); + var q = MiniExcel.QueryAsync(path, useHeaderRow: true, configuration: config).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("V1", rows[2].Test1); Assert.Equal("V2", rows[5].Test2); @@ -624,7 +624,7 @@ public async Task Issue227() { var path = PathHelper.GetFile("xlsx/TestIssue227.xlsm"); { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(100, rows.Count); @@ -703,7 +703,7 @@ public async Task Issue223() public async Task Issue222() { var path = PathHelper.GetFile("xlsx/TestIssue222.xlsx"); - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(typeof(DateTime), rows[1].A.GetType()); Assert.Equal(new DateTime(2021, 4, 29), rows[1].A); @@ -718,7 +718,7 @@ public async Task Issue147() { { var path = PathHelper.GetFile("xlsx/TestIssue147.xlsx"); - var q = await MiniExcel.QueryAsync(path, useHeaderRow: false, startCell: "C3", sheetName: "Sheet1"); + var q = MiniExcel.QueryAsync(path, useHeaderRow: false, startCell: "C3", sheetName: "Sheet1").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(["C", "D", "E"], (rows[0] as IDictionary)?.Keys); @@ -740,7 +740,7 @@ public async Task Issue147() { var path = PathHelper.GetFile("xlsx/TestIssue147.xlsx"); - var q = await MiniExcel.QueryAsync(path, useHeaderRow: true, startCell: "C3", sheetName: "Sheet1"); + var q = MiniExcel.QueryAsync(path, useHeaderRow: true, startCell: "C3", sheetName: "Sheet1").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(["Column1", "Column2", "Column3"], (rows[0] as IDictionary)?.Keys); @@ -779,7 +779,7 @@ public async Task Issue211() Assert.Single(rowsWritten); Assert.Equal(3, rowsWritten[0]); - var q = await MiniExcel.QueryAsync(path.ToString(), true); + var q = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(1.0, rows[0].Test1); Assert.Equal(2.0, rows[0].Test2); @@ -806,7 +806,7 @@ public async Task EmptyDataReaderIssue() Assert.Single(rowsWritten); Assert.Equal(0, rowsWritten[0]); - var q = await MiniExcel.QueryAsync(path.ToString(), true); + var q = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Empty(rows); } @@ -862,7 +862,7 @@ public async Task IssueI3OSKV() var value = new[] { new { Test = "12345678901234567890" } }; await MiniExcel.SaveAsAsync(path.ToString(), value); - var q = await MiniExcel.QueryAsync(path.ToString(), true); + var q = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var A2 = q.First().Test; Assert.Equal("12345678901234567890", A2); } @@ -872,7 +872,7 @@ public async Task IssueI3OSKV() var value = new[] { new { Test = 123456.789 } }; await MiniExcel.SaveAsAsync(path.ToString(), value); - var q = await MiniExcel.QueryAsync(path.ToString(), true); + var q = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var A2 = q.First().Test; Assert.Equal(123456.789, A2); } @@ -886,7 +886,7 @@ public async Task IssueI3OSKV() public async Task Issue220() { var path = PathHelper.GetFile("xlsx/TestIssue220.xlsx"); - var rows = await MiniExcel.QueryAsync(path, useHeaderRow: true); + var rows = MiniExcel.QueryAsync(path, useHeaderRow: true).ToBlockingEnumerable(); var result = rows .GroupBy(s => s.PRT_ID) .Select(g => new @@ -912,7 +912,7 @@ public async Task Issue215() await using var stream = new MemoryStream(); await stream.SaveAsAsync(new[] { new { V = "test1" }, new { V = "test2" } }); - var q = (await stream.QueryAsync(true)).Cast>(); + var q = (stream.QueryAsync(true).ToBlockingEnumerable()).Cast>(); var rows = q.ToList(); Assert.Equal("test1", rows[0]["V"]); @@ -954,7 +954,7 @@ public async Task Issue89() Assert.Single(rowsWritten); Assert.Equal(3, rowsWritten[0]); - var q2 = await MiniExcel.QueryAsync(outputPath); + var q2 = MiniExcel.QueryAsync(outputPath).ToBlockingEnumerable(); var rows2 = q2.ToList(); Assert.Equal(Issue89VO.WorkState.OnDuty, rows2[0].State); Assert.Equal(Issue89VO.WorkState.Fired, rows2[1].State); @@ -964,7 +964,7 @@ public async Task Issue89() //xlsx { var path = PathHelper.GetFile("xlsx/TestIssue89.xlsx"); - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(Issue89VO.WorkState.OnDuty, rows[0].State); Assert.Equal(Issue89VO.WorkState.Fired, rows[1].State); @@ -975,7 +975,7 @@ public async Task Issue89() Assert.Single(rowsWritten); Assert.Equal(3, rowsWritten[0]); - var q1 = await MiniExcel.QueryAsync(outputPath); + var q1 = MiniExcel.QueryAsync(outputPath).ToBlockingEnumerable(); var rows2 = q1.ToList(); Assert.Equal(Issue89VO.WorkState.OnDuty, rows2[0].State); Assert.Equal(Issue89VO.WorkState.Fired, rows2[1].State); @@ -1016,7 +1016,7 @@ public async Task Issue217() Assert.Single(rowsWritten); Assert.Equal(2, rowsWritten[0]); - var q = await MiniExcel.QueryAsync(path.ToString()); + var q = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("Name", rows[0].B); Assert.Equal("Limit", rows[0].C); @@ -1027,7 +1027,7 @@ public async Task Issue217() using var path = AutoDeletingPath.Create(ExcelType.CSV); await MiniExcel.SaveAsAsync(path.ToString(), table); - var q = await MiniExcel.QueryAsync(path.ToString()); + var q = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("Name", rows[0].B); Assert.Equal("Limit", rows[0].C); @@ -1074,7 +1074,7 @@ public async Task Issue207() }; await MiniExcel.SaveAsByTemplateAsync(path, templatePath, value); - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("項目1", rows[0].A); @@ -1121,7 +1121,7 @@ public async Task Issue207() await MiniExcel.SaveAsByTemplateAsync(path, templatePath, value); - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("項目1", rows[0].A); Assert.Equal("[]內容1,[]內容2,[]內容3,[]內容4,[]內容5", rows[0].C); @@ -1151,7 +1151,7 @@ public async Task Issue87() }; await using var stream = File.OpenRead(templatePath); - var q = await MiniExcel.QueryAsync(templatePath); + var q = MiniExcel.QueryAsync(templatePath).ToBlockingEnumerable(); var rows = q.ToList(); await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); @@ -1232,7 +1232,7 @@ public async Task Issue193() foreach (var sheetName in MiniExcel.GetSheetNames(path)) { - var q = await MiniExcel.QueryAsync(path, sheetName: sheetName); + var q = MiniExcel.QueryAsync(path, sheetName: sheetName).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(9, rows.Count); @@ -1285,7 +1285,7 @@ public async Task Issue193() }; await MiniExcel.SaveAsByTemplateAsync(path, templatePath, value); - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("FooCompany", rows[0].A); Assert.Equal("Jack", rows[2].B); @@ -1317,7 +1317,7 @@ public async Task Issue142() await MiniExcel.SaveAsAsync(path, new[] { new Issue142VO { MyProperty1 = "MyProperty1", MyProperty2 = "MyProperty2", MyProperty3 = "MyProperty3", MyProperty4 = "MyProperty4", MyProperty5 = "MyProperty5", MyProperty6 = "MyProperty6", MyProperty7 = "MyProperty7" } }); { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("MyProperty4", rows[0].A); Assert.Equal("CustomColumnName", rows[0].B); //note @@ -1337,7 +1337,7 @@ public async Task Issue142() } { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("MyProperty4", rows[0].MyProperty4); @@ -1363,7 +1363,7 @@ public async Task Issue142() Assert.Equal(expected, await File.ReadAllTextAsync(path)); { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("MyProperty4", rows[0].MyProperty4); @@ -1389,19 +1389,19 @@ public async Task Issue142_Query() const string path = "../../../../../samples/xlsx/TestIssue142.xlsx"; const string pathCsv = "../../../../../samples/xlsx/TestIssue142.csv"; { - var rows = (await MiniExcel.QueryAsync(path)).ToList(); + var rows = MiniExcel.QueryAsync(path).ToBlockingEnumerable().ToList(); Assert.Equal(0, rows[0].MyProperty1); } { await Assert.ThrowsAsync(async () => { - var q = (await MiniExcel.QueryAsync(path)).ToList(); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable().ToList(); }); } { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("CustomColumnName", rows[0].MyProperty1); Assert.Null(rows[0].MyProperty7); @@ -1413,7 +1413,7 @@ await Assert.ThrowsAsync(async () => } { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal("CustomColumnName", rows[0].MyProperty1); Assert.Null(rows[0].MyProperty7); @@ -1554,7 +1554,7 @@ public async Task Issue157() Assert.Single(rowsWritten); Assert.Equal(5, rowsWritten[0]); - var q = await MiniExcel.QueryAsync(path, sheetName: "Sheet1"); + var q = MiniExcel.QueryAsync(path, sheetName: "Sheet1").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(6, rows.Count); Assert.Equal("Sheet1", MiniExcel.GetSheetNames(path).First()); @@ -1567,7 +1567,7 @@ public async Task Issue157() { const string path = "../../../../../samples/xlsx/TestIssue157.xlsx"; { - var q = await MiniExcel.QueryAsync(path, sheetName: "Sheet1"); + var q = MiniExcel.QueryAsync(path, sheetName: "Sheet1").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(6, rows.Count); Assert.Equal("Sheet1", MiniExcel.GetSheetNames(path).First()); @@ -1580,7 +1580,7 @@ public async Task Issue157() } { - var q = await MiniExcel.QueryAsync(path, sheetName: "Sheet1"); + var q = MiniExcel.QueryAsync(path, sheetName: "Sheet1").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(5, rows.Count); @@ -1614,7 +1614,7 @@ public async Task Issue149() { const string path = "../../../../../samples/xlsx/TestIssue149.xlsx"; - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.Select(s => (string)s.A).ToList(); for (int i = 0; i < chars.Length; i++) @@ -1633,7 +1633,7 @@ public async Task Issue149() var input = chars.Select(s => new { Test = s.ToString() }); await MiniExcel.SaveAsAsync(path, input); - var q = await MiniExcel.QueryAsync(path, true); + var q = MiniExcel.QueryAsync(path, true).ToBlockingEnumerable(); var rows = q.Select(s => (string)s.Test).ToList(); for (int i = 0; i < chars.Length; i++) @@ -1653,7 +1653,7 @@ public async Task Issue149() var input = chars.Select(s => new { Test = s.ToString() }); await MiniExcel.SaveAsAsync(path, input); - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.Select(s => s.Test).ToList(); for (int i = 0; i < chars.Length; i++) @@ -1679,7 +1679,7 @@ private class Issue149VO public async Task Issue153() { const string path = "../../../../../samples/xlsx/TestIssue153.xlsx"; - var q = await MiniExcel.QueryAsync(path, true); + var q = MiniExcel.QueryAsync(path, true).ToBlockingEnumerable(); var rows = q.First() as IDictionary; Assert.Equal( @@ -1698,7 +1698,7 @@ public async Task Issue137() var path = "../../../../../samples/xlsx/TestIssue137.xlsx"; { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); var first = rows[0] as IDictionary; // https://user-images.githubusercontent.com/12729184/113266322-ba06e400-9307-11eb-9521-d36abfda75cc.png Assert.Equal(["A", "B", "C", "D", "E", "F", "G", "H"], first?.Keys.ToArray()); @@ -1734,7 +1734,7 @@ public async Task Issue137() // dynamic query with head { - var q = await MiniExcel.QueryAsync(path, true); + var q = MiniExcel.QueryAsync(path, true).ToBlockingEnumerable(); var rows = q.ToList(); var first = rows[0] as IDictionary; // https://user-images.githubusercontent.com/12729184/113266322-ba06e400-9307-11eb-9521-d36abfda75cc.png Assert.Equal(["比例", "商品", "滿倉口數", "0", "1為港幣 0為台幣"], first?.Keys.ToArray()); @@ -1756,7 +1756,7 @@ public async Task Issue137() } { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(10, rows.Count); @@ -1790,7 +1790,7 @@ public async Task Issue138() { const string path = "../../../../../samples/xlsx/TestIssue138.xlsx"; { - var q = await MiniExcel.QueryAsync(path, true); + var q = MiniExcel.QueryAsync(path, true).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(6, rows.Count); @@ -1816,7 +1816,7 @@ public async Task Issue138() } { - var q = await MiniExcel.QueryAsync(path); + var q = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(6, rows.Count); Assert.Equal(new DateTime(2021, 3, 1), rows[0].Date); diff --git a/tests/MiniExcelTests/MiniExcelIssueTests.cs b/tests/MiniExcelTests/MiniExcelIssueTests.cs index a957c675..8b3a13b2 100644 --- a/tests/MiniExcelTests/MiniExcelIssueTests.cs +++ b/tests/MiniExcelTests/MiniExcelIssueTests.cs @@ -717,7 +717,7 @@ public async Task TestIssue338() Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); { var path = PathHelper.GetFile("csv/TestIssue338.csv"); - var row = (await MiniExcel.QueryAsync(path)).FirstOrDefault(); + var row = MiniExcel.QueryAsync(path).ToBlockingEnumerable().FirstOrDefault(); Assert.Equal("���IJ�������", row!.A); } { @@ -726,7 +726,7 @@ public async Task TestIssue338() { StreamReaderFunc = stream => new StreamReader(stream, Encoding.GetEncoding("gb2312")) }; - var row = (await MiniExcel.QueryAsync(path, configuration: config)).FirstOrDefault(); + var row = MiniExcel.QueryAsync(path, configuration: config).ToBlockingEnumerable().FirstOrDefault(); Assert.Equal("中文测试内容", row!.A); } { @@ -737,7 +737,7 @@ public async Task TestIssue338() }; await using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { - var row = (await stream.QueryAsync(configuration: config, excelType: ExcelType.CSV)).FirstOrDefault(); + var row = stream.QueryAsync(configuration: config, excelType: ExcelType.CSV).ToBlockingEnumerable().FirstOrDefault(); Assert.Equal("中文测试内容", row!.A); } } @@ -4066,7 +4066,7 @@ static IEnumerable GetTestData() memoryStream.Position = 0; - var queryData = (memoryStream.QueryAsync()).ToBlockingEnumerable().ToList(); + var queryData = (memoryStream.QueryAsync().ToBlockingEnumerable()).ToList(); Assert.Equal(testData.Count(), queryData.Count); diff --git a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs index d477a28d..218c6241 100644 --- a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs @@ -21,7 +21,7 @@ public async Task SaveAsControlChracter() { using var file = AutoDeletingPath.Create(); var path = file.ToString(); - + char[] chars = [ '\u0000','\u0001','\u0002','\u0003','\u0004','\u0005','\u0006','\u0007','\u0008', @@ -35,8 +35,8 @@ public async Task SaveAsControlChracter() var input = chars.Select(s => new { Test = s.ToString() }); await MiniExcel.SaveAsAsync(path, input); - var rows2 = (await MiniExcel.QueryAsync(path, true)).ToArray(); - var rows1 = (await MiniExcel.QueryAsync(path)).ToArray(); + var rows2 = MiniExcel.QueryAsync(path, true).ToBlockingEnumerable().ToArray(); + var rows1 = MiniExcel.QueryAsync(path).ToBlockingEnumerable().ToArray(); } private class SaveAsControlChracterVO @@ -82,7 +82,7 @@ public async Task CustomAttributeWihoutVaildPropertiesTest() const string path = "../../../../../samples/xlsx/TestCustomExcelColumnAttribute.xlsx"; await Assert.ThrowsAsync(async () => { - _ = (await MiniExcel.QueryAsync(path)).ToList(); + _ = MiniExcel.QueryAsync(path).ToBlockingEnumerable().ToList(); }); } @@ -90,7 +90,7 @@ await Assert.ThrowsAsync(async () => public async Task QueryCustomAttributesTest() { const string path = "../../../../../samples/xlsx/TestCustomExcelColumnAttribute.xlsx"; - var rows = (await MiniExcel.QueryAsync(path)).ToList(); + var rows = MiniExcel.QueryAsync(path).ToBlockingEnumerable().ToList(); Assert.Equal("Column1", rows[0].Test1); Assert.Equal("Column2", rows[0].Test2); @@ -105,8 +105,8 @@ public async Task QueryCustomAttributesTest() public async Task QueryCustomAttributes2Test() { const string path = "../../../../../samples/xlsx/TestCustomExcelColumnAttribute.xlsx"; - var rows = (await MiniExcel.QueryAsync(path)).ToList(); - + var rows = MiniExcel.QueryAsync(path).ToBlockingEnumerable().ToList(); + Assert.Equal("Column1", rows[0].Test1); Assert.Equal("Column2", rows[0].Test2); Assert.Null(rows[0].Test3); @@ -128,12 +128,12 @@ public async Task SaveAsCustomAttributesTest() Test3 = "Test3", Test4 = "Test4", }); - + await MiniExcel.SaveAsAsync(path.ToString(), input); - var d = await MiniExcel.QueryAsync(path.ToString(), true); + var d = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var rows = d.ToList(); var first = rows[0] as IDictionary; - + Assert.Equal(3, rows.Count); Assert.Equal(["Column1", "Column2", "Test5", "Test7", "Test6", "Test4"], first?.Keys); Assert.Equal("Test1", rows[0].Column1); @@ -155,9 +155,9 @@ public async Task SaveAsCustomAttributes2Test() Test3 = "Test3", Test4 = "Test4", }); - + await MiniExcel.SaveAsAsync(path.ToString(), input); - var d = await MiniExcel.QueryAsync(path.ToString(), true); + var d = MiniExcel.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); var rows = d.ToList(); var first = rows[0] as IDictionary; @@ -182,19 +182,19 @@ private class CustomAttributesWihoutVaildPropertiesTestPoco public async Task QueryCastToIDictionary() { const string path = "../../../../../samples/xlsx/TestCenterEmptyRow/TestCenterEmptyRow.xlsx"; - foreach (IDictionary row in await MiniExcel.QueryAsync(path)) + foreach (IDictionary row in MiniExcel.QueryAsync(path).ToBlockingEnumerable()) { _ = row; } } - + [Fact] public async Task CenterEmptyRowsQueryTest() { const string path = "../../../../../samples/xlsx/TestCenterEmptyRow/TestCenterEmptyRow.xlsx"; await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync()).Cast>(); + var d = (stream.QueryAsync().ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal("a", rows[0]["A"]); Assert.Equal("b", rows[0]["B"]); @@ -230,7 +230,7 @@ public async Task CenterEmptyRowsQueryTest() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(1d, rows[0]["a"]); Assert.Null(rows[0]["b"]); @@ -264,7 +264,7 @@ public async Task TestDynamicQueryBasic_WithoutHead() { const string path = "../../../../../samples/xlsx/TestDynamicQueryBasic_WithoutHead.xlsx"; await using var stream = File.OpenRead(path); - var d = (await stream.QueryAsync()).Cast>(); + var d = (stream.QueryAsync().ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal("MiniExcel", rows[0]["A"]); @@ -279,7 +279,7 @@ public async Task TestDynamicQueryBasic_useHeaderRow() const string path = "../../../../../samples/xlsx/TestDynamicQueryBasic.xlsx"; await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); @@ -288,7 +288,7 @@ public async Task TestDynamicQueryBasic_useHeaderRow() } { - var d = await MiniExcel.QueryAsync(path, useHeaderRow: true); + var d = MiniExcel.QueryAsync(path, useHeaderRow: true).ToBlockingEnumerable(); var rows = d.ToList(); Assert.Equal("MiniExcel", rows[0].Column1); Assert.Equal(1d, rows[0].Column2); @@ -368,12 +368,12 @@ public async Task TestDatetimeSpanFormat_ClosedXml() { const string path = "../../../../../samples/xlsx/TestDatetimeSpanFormat_ClosedXml.xlsx"; await using var stream = FileHelper.OpenRead(path); - - var d = (await stream.QueryAsync()).Cast>(); + + var d = (stream.QueryAsync().ToBlockingEnumerable()).Cast>(); var row = d.First(); var a = row["A"]; var b = row["B"]; - + Assert.Equal(DateTime.Parse("2021-03-20T23:39:42.3130000"), (DateTime)a); Assert.Equal(TimeSpan.FromHours(10), (TimeSpan)b); } @@ -390,7 +390,7 @@ public async Task LargeFileQueryStrongTypeMapping_Test() Assert.Equal("HelloWorld3", rows[1].HelloWorld1); } { - var d = await MiniExcel.QueryAsync(path); + var d = MiniExcel.QueryAsync(path).ToBlockingEnumerable(); var rows = d.Take(2).ToList(); Assert.Equal("HelloWorld2", rows[0].HelloWorld1); Assert.Equal("HelloWorld3", rows[1].HelloWorld1); @@ -411,10 +411,10 @@ public async Task QueryExcelDataReaderCheckTest(string path) var exceldatareaderResult = reader.AsDataSet(); await using var stream = File.OpenRead(path); - var d = await stream.QueryAsync(); + var d = stream.QueryAsync().ToBlockingEnumerable(); var rows = d.ToList(); Assert.Equal(exceldatareaderResult.Tables[0].Rows.Count, rows.Count); - + foreach (IDictionary row in rows) { var rowIndex = rows.IndexOf(row); @@ -432,8 +432,8 @@ public async Task QuerySheetWithoutRAttribute() { const string path = "../../../../../samples/xlsx/TestWihoutRAttribute.xlsx"; await using var stream = File.OpenRead(path); - - var d = (await stream.QueryAsync()).Cast>(); + + var d = (stream.QueryAsync().ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); var keys = rows.First().Keys; @@ -456,7 +456,7 @@ public async Task FixDimensionJustOneColumnParsingError_Test() { const string path = "../../../../../samples/xlsx/TestDimensionC3.xlsx"; await using var stream = File.OpenRead(path); - var d = await stream.QueryAsync(); + var d = stream.QueryAsync().ToBlockingEnumerable(); var rows = d.ToList(); var keys = (rows.First() as IDictionary)?.Keys; Assert.Equal(3, keys?.Count); @@ -473,19 +473,19 @@ public async Task SaveAsFileWithDimensionByICollection() { //List { - List values= + List values = [ new() { A = "A", B = "B" }, new() { A = "A", B = "B" } ]; - + using (var file = AutoDeletingPath.Create()) { var path = file.ToString(); await MiniExcel.SaveAsAsync(path, values); await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: false)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(3, rows.Count); Assert.Equal("A", rows[0]["A"]); @@ -495,7 +495,7 @@ public async Task SaveAsFileWithDimensionByICollection() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(2, rows.Count); Assert.Equal("A", rows[0]["A"]); @@ -504,7 +504,7 @@ public async Task SaveAsFileWithDimensionByICollection() Assert.Equal("A1:B3", Helpers.GetFirstSheetDimensionRefValue(path)); } - + using var newPath = AutoDeletingPath.Create(); await MiniExcel.SaveAsAsync(newPath.ToString(), values, false); Assert.Equal("A1:B2", Helpers.GetFirstSheetDimensionRefValue(newPath.ToString())); @@ -519,7 +519,7 @@ public async Task SaveAsFileWithDimensionByICollection() await MiniExcel.SaveAsAsync(path, values, false); await using (var stream = File.OpenRead(path)) { - var d = await stream.QueryAsync(useHeaderRow: false); + var d = stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable(); var rows = d.ToList(); Assert.Empty(rows); } @@ -533,7 +533,7 @@ public async Task SaveAsFileWithDimensionByICollection() await MiniExcel.SaveAsAsync(path, values); { await using var stream = File.OpenRead(path); - var d = await stream.QueryAsync(useHeaderRow: false); + var d = stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable(); var rows = d.ToList(); Assert.Single(rows); } @@ -548,7 +548,7 @@ public async Task SaveAsFileWithDimensionByICollection() new { A = "A", B = "B" }, new { A = "A", B = "B" }, }; - + using (var file = AutoDeletingPath.Create()) { var path = file.ToString(); @@ -556,7 +556,7 @@ public async Task SaveAsFileWithDimensionByICollection() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: false)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(3, rows.Count); Assert.Equal("A", rows[0]["A"]); @@ -566,7 +566,7 @@ public async Task SaveAsFileWithDimensionByICollection() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(2, rows.Count); Assert.Equal("A", rows[0]["A"]); @@ -603,9 +603,9 @@ public async Task SaveAsFileWithDimension() Assert.Equal("A1", Helpers.GetFirstSheetDimensionRefValue(path)); { await using var stream = File.OpenRead(path); - var d = await stream.QueryAsync(); + var d = stream.QueryAsync().ToBlockingEnumerable(); var rows = d.ToList(); - Assert.Single(rows); + Assert.Single(rows); } await MiniExcel.SaveAsAsync(path, table, printHeader: false, overwriteFile: true); Assert.Equal("A1", Helpers.GetFirstSheetDimensionRefValue(path)); @@ -614,7 +614,7 @@ public async Task SaveAsFileWithDimension() using var file = AutoDeletingPath.Create(); var path = file.ToString(); using var table = new DataTable(); - + table.Columns.Add("a", typeof(string)); table.Columns.Add("b", typeof(decimal)); table.Columns.Add("c", typeof(bool)); @@ -627,7 +627,7 @@ public async Task SaveAsFileWithDimension() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(2, rows.Count); Assert.Equal(@"""<>+-*//}{\\n", rows[0]["a"]); @@ -638,7 +638,7 @@ public async Task SaveAsFileWithDimension() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync()).Cast>(); + var d = (stream.QueryAsync().ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(3, rows.Count); Assert.Equal("a", rows[0]["A"]); @@ -647,7 +647,7 @@ public async Task SaveAsFileWithDimension() Assert.Equal("d", rows[0]["D"]); } - await MiniExcel.SaveAsAsync(path, table, printHeader: false, overwriteFile:true); + await MiniExcel.SaveAsAsync(path, table, printHeader: false, overwriteFile: true); Assert.Equal("A1:D2", Helpers.GetFirstSheetDimensionRefValue(path)); } @@ -657,7 +657,7 @@ public async Task SaveAsFileWithDimension() table.Columns.Add("a", typeof(string)); table.Rows.Add("A"); table.Rows.Add("B"); - + await MiniExcel.SaveAsAsync(path.ToString(), table); Assert.Equal("A1:A3", Helpers.GetFirstSheetDimensionRefValue(path.ToString())); } @@ -713,19 +713,19 @@ public async Task QueryByLINQExtensionsVoidTaskLargeFileOOMTest() const string path = "../../../../../benchmarks/MiniExcel.Benchmarks/Test1,000,000x10.xlsx"; { - var row = (await MiniExcel.QueryAsync(path)).First(); + var row = (MiniExcel.QueryAsync(path).ToBlockingEnumerable()).First(); Assert.Equal("HelloWorld1", row.A); } await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync()).Cast>(); + var d = (stream.QueryAsync().ToBlockingEnumerable()).Cast>(); var row = d.First(); Assert.Equal("HelloWorld1", row["A"]); } { - var d = (await MiniExcel.QueryAsync(path)).Cast>(); + var d = (MiniExcel.QueryAsync(path).ToBlockingEnumerable()).Cast>(); var rows = d.Take(10); Assert.Equal(10, rows.Count()); } @@ -744,7 +744,7 @@ public async Task EmptyTest() await using (var stream = File.OpenRead(path.ToString())) { - var row = await stream.QueryAsync(useHeaderRow: true); + var row = stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable(); Assert.Empty(row); } } @@ -765,7 +765,7 @@ public async Task SaveAsByIEnumerableIDictionary() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: false)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal("Column1", rows[0]["A"]); Assert.Equal("Column2", rows[0]["B"]); @@ -777,7 +777,7 @@ public async Task SaveAsByIEnumerableIDictionary() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(2, rows.Count); Assert.Equal("MiniExcel", rows[0]["Column1"]); @@ -802,7 +802,7 @@ public async Task SaveAsByIEnumerableIDictionary() await using (var stream = File.OpenRead(path)) { - var d = await stream.QueryAsync(useHeaderRow: false); + var d = stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable(); var rows = d.ToList(); Assert.Equal(3, rows.Count); } @@ -834,7 +834,7 @@ public async Task SaveAsByIEnumerableIDictionaryWithDynamicConfiguration() await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal(2, rows.Count); Assert.Equal("Name Column", rows[0].Keys.ElementAt(0)); @@ -863,7 +863,7 @@ public async Task SaveAsFrozenRowsAndColumnsTest() await MiniExcel.SaveAsAsync( path, - new[] + new[] { new { Column1 = "MiniExcel", Column2 = 1 }, new { Column1 = "Github", Column2 = 2} @@ -873,7 +873,7 @@ await MiniExcel.SaveAsAsync( await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: true)).ToList(); + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).ToList(); Assert.Equal("MiniExcel", rows[0].Column1); Assert.Equal(1, rows[0].Column2); @@ -890,7 +890,7 @@ await MiniExcel.SaveAsAsync( table.Columns.Add("d", typeof(DateTime)); table.Rows.Add("some text", 1234567890, true, DateTime.Now); table.Rows.Add("Hello World", -1234567890, false, DateTime.Now.Date); - + using var pathTable = AutoDeletingPath.Create(); await MiniExcel.SaveAsAsync(pathTable.ToString(), table, configuration: config); Assert.Equal("A1:D3", Helpers.GetFirstSheetDimensionRefValue(pathTable.ToString())); @@ -918,7 +918,7 @@ public async Task SaveAsByDapperRows() await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: true)).Cast>().ToList(); + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); Assert.Equal("Github", rows[1]["Column1"]); @@ -934,13 +934,13 @@ public async Task SaveAsByDapperRows() await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: false)).ToList(); + var rows = (stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable()).ToList(); Assert.Empty(rows); } await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: true)).ToList(); + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).ToList(); Assert.Empty(rows); } Assert.Equal("A1", Helpers.GetFirstSheetDimensionRefValue(path)); @@ -955,7 +955,7 @@ public async Task SaveAsByDapperRows() await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: false)).Cast>().ToList(); + var rows = (stream.QueryAsync(useHeaderRow: false).ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal("Column1", rows[0]["A"]); Assert.Equal("Column2", rows[0]["B"]); Assert.Equal("MiniExcel", rows[1]["A"]); @@ -966,7 +966,7 @@ public async Task SaveAsByDapperRows() await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: true)).Cast>().ToList(); + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); Assert.Equal("Github", rows[1]["Column1"]); @@ -993,8 +993,8 @@ public async Task QueryByStrongTypeParameterTest() await MiniExcel.SaveAsAsync(path, values); await using var stream = File.OpenRead(path); - var rows = (await stream.QueryAsync(useHeaderRow: true)).Cast>().ToList(); - + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>().ToList(); + Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); Assert.Equal("Github", rows[1]["Column1"]); @@ -1014,8 +1014,8 @@ public async Task QueryByDictionaryStringAndObjectParameterTest() await MiniExcel.SaveAsAsync(path, values); await using var stream = File.OpenRead(path); - var rows = (await stream.QueryAsync(useHeaderRow: true)).Cast>().ToList(); - + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>().ToList(); + Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); Assert.Equal("Github", rows[1]["Column1"]); @@ -1041,14 +1041,14 @@ public async Task SQLiteInsertTest() await using (var transaction = connection.BeginTransaction()) await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync()).Cast>(); + var rows = (stream.QueryAsync().ToBlockingEnumerable()).Cast>(); foreach (var row in rows) await connection.ExecuteAsync( "insert into T (A,B) values (@A,@B)", - new { A = row["A"], B = row["B"] }, + new { A = row["A"], B = row["B"] }, transaction: transaction ); - + await transaction.CommitAsync(); } } @@ -1065,8 +1065,8 @@ public async Task SaveAsBasicCreateTest() { using var file = AutoDeletingPath.Create(); var path = file.ToString(); - - await MiniExcel.SaveAsAsync(path, new[] + + await MiniExcel.SaveAsAsync(path, new[] { new { Column1 = "MiniExcel", Column2 = 1 }, new { Column1 = "Github", Column2 = 2} @@ -1074,7 +1074,7 @@ await MiniExcel.SaveAsAsync(path, new[] await using (var stream = File.OpenRead(path)) { - var d = (await stream.QueryAsync(useHeaderRow: true)).Cast>(); + var d = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>(); var rows = d.ToList(); Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); @@ -1090,8 +1090,8 @@ public async Task SaveAsBasicStreamTest() { using var file = AutoDeletingPath.Create(); var path = file.ToString(); - - var values = new[] + + var values = new[] { new { Column1 = "MiniExcel", Column2 = 1 }, new { Column1 = "Github", Column2 = 2} @@ -1103,7 +1103,7 @@ public async Task SaveAsBasicStreamTest() await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: true)).Cast>().ToList(); + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); Assert.Equal("Github", rows[1]["Column1"]); @@ -1113,7 +1113,7 @@ public async Task SaveAsBasicStreamTest() { using var file = AutoDeletingPath.Create(); var path = file.ToString(); - var values = new[] + var values = new[] { new { Column1 = "MiniExcel", Column2 = 1 }, new { Column1 = "Github", Column2 = 2} @@ -1128,7 +1128,7 @@ public async Task SaveAsBasicStreamTest() await using (var stream = File.OpenRead(path)) { - var rows = (await stream.QueryAsync(useHeaderRow: true)).Cast>().ToList(); + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal("MiniExcel", rows[0]["Column1"]); Assert.Equal(1d, rows[0]["Column2"]); Assert.Equal("Github", rows[1]["Column1"]); @@ -1141,7 +1141,7 @@ public async Task SaveAsBasicStreamTest() public async Task SaveAsSpecialAndTypeCreateTest() { using var path = AutoDeletingPath.Create(); - await MiniExcel.SaveAsAsync(path.ToString(), new[] + await MiniExcel.SaveAsAsync(path.ToString(), new[] { new { a = @"""<>+-*//}{\\n", b = 1234567890, c = true, d = DateTime.Now }, new { a = "Hello World", b = -1234567890, c = false, d = DateTime.Now.Date} @@ -1156,12 +1156,12 @@ public async Task SaveAsFileEpplusCanReadTest() using var path = AutoDeletingPath.Create(); var now = DateTime.Now; - await MiniExcel.SaveAsAsync(path.ToString(), new[] + await MiniExcel.SaveAsAsync(path.ToString(), new[] { new { a = @"""<>+-*//}{\\n", b = 1234567890, c = true, d = now}, new { a = "Hello World", b = -1234567890, c = false, d = now.Date} }); - + using var p = new ExcelPackage(new FileInfo(path.ToString())); var ws = p.Workbook.Worksheets.First(); @@ -1182,7 +1182,7 @@ public async Task SavaAsClosedXmlCanReadTest() var now = DateTime.Now; using var path = AutoDeletingPath.Create(); - await MiniExcel.SaveAsAsync(path.ToString(), new[] + await MiniExcel.SaveAsAsync(path.ToString(), new[] { new { a = @"""<>+-*//}{\\n", b = 1234567890, c = true, d = now}, new { a = "Hello World", b = -1234567890, c = false, d = now.Date} @@ -1216,7 +1216,7 @@ await MiniExcel.SaveAsAsync(path.ToString(), new[] var allParts = zip.GetParts() .Select(s => new { s.CompressionOption, s.ContentType, s.Uri, s.Package.GetType().Name }) .ToDictionary(s => s.Uri.ToString(), s => s); - + Assert.True(allParts["/xl/styles.xml"].ContentType == "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); Assert.True(allParts["/xl/workbook.xml"].ContentType == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"); Assert.True(allParts["/xl/worksheets/sheet1.xml"].ContentType == "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"); @@ -1235,7 +1235,7 @@ await Assert.ThrowsAsync(async () => cts.CancelAsync(); await using var stream = FileHelper.OpenRead(path); - var rows = (await stream.QueryAsync(cancellationToken: cts.Token)).ToList(); + var rows = stream.QueryAsync(ct: cts.Token).ToBlockingEnumerable(cts.Token).ToList(); }); } @@ -1255,9 +1255,9 @@ await Assert.ThrowsAsync(async () => }); await using var stream = FileHelper.OpenRead(path); - var d = stream.QueryAsync(cancellationToken: cts.Token); + var d = stream.QueryAsync(ct: cts.Token).ToBlockingEnumerable(cts.Token); await cancelTask; - _ = (await d).ToList(); + _ = d.ToList(); }); } @@ -1267,7 +1267,7 @@ public async Task DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingIDataRe using var path = AutoDeletingPath.Create(); var dateTime = DateTime.Now; var onlyDate = DateOnly.FromDateTime(dateTime); - + using var table = new DataTable(); table.Columns.Add("Column1", typeof(string)); table.Columns.Add("Column2", typeof(int)); @@ -1306,7 +1306,7 @@ public async Task DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingIDataRe await MiniExcel.SaveAsAsync(path.ToString(), reader, configuration: configuration); await using var stream = File.OpenRead(path.ToString()); - var rows = (await stream.QueryAsync(useHeaderRow: true)) + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()) .Cast>() .ToList(); @@ -1335,7 +1335,7 @@ public async Task DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingDataTab using var path = AutoDeletingPath.Create(); var dateTime = DateTime.Now; var onlyDate = DateOnly.FromDateTime(dateTime); - + using var table = new DataTable(); table.Columns.Add("Column1", typeof(string)); table.Columns.Add("Column2", typeof(int)); @@ -1372,7 +1372,7 @@ public async Task DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingDataTab await MiniExcel.SaveAsAsync(path.ToString(), table, configuration: configuration); await using var stream = File.OpenRead(path.ToString()); - var rows = (await stream.QueryAsync(useHeaderRow: true)) + var rows = (stream.QueryAsync(useHeaderRow: true).ToBlockingEnumerable()) .Cast>() .ToList(); @@ -1411,7 +1411,7 @@ public async Task SaveAsByMiniExcelDataReader() { using var path2 = AutoDeletingPath.Create(); await MiniExcel.SaveAsAsync(path2.ToString(), reader); - var results = (await MiniExcel.QueryAsync(path2.ToString())).ToList(); + var results = MiniExcel.QueryAsync(path2.ToString()).ToBlockingEnumerable().ToList(); Assert.True(results.Count == 2); Assert.True(results.First().Column1 == "MiniExcel"); @@ -1528,7 +1528,7 @@ public async Task InsertSheetTest() } ] }); - + using var p = new ExcelPackage(new FileInfo(path)); var sheet3 = p.Workbook.Worksheets[2]; @@ -1552,7 +1552,7 @@ public async Task InsertCsvTest() var path = file.ToString(); { - var value = new[] + var value = new[] { new { ID=1,Name ="Jack",InDate=new DateTime(2021,01,03)}, new { ID=2,Name ="Henry",InDate=new DateTime(2020,05,03)}, @@ -1586,7 +1586,7 @@ public async Task InsertCsvTest() new { ID=4,Name ="Frank",InDate=new DateTime(2021,06,07)}, new { ID=5,Name ="Gloria",InDate=new DateTime(2022,05,03)}, }; - + await MiniExcel.InsertAsync(path, value); var content = await File.ReadAllTextAsync(path); Assert.Equal( diff --git a/tests/MiniExcelTests/MiniExcelOpenXmlMultipleSheetAsyncTests.cs b/tests/MiniExcelTests/MiniExcelOpenXmlMultipleSheetAsyncTests.cs index d8de3b8d..a0ce004c 100644 --- a/tests/MiniExcelTests/MiniExcelOpenXmlMultipleSheetAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelOpenXmlMultipleSheetAsyncTests.cs @@ -9,21 +9,21 @@ public async Task SpecifySheetNameQueryTest() { const string path = "../../../../../samples/xlsx/TestMultiSheet.xlsx"; { - var q = await MiniExcel.QueryAsync(path, sheetName: "Sheet3"); + var q = MiniExcel.QueryAsync(path, sheetName: "Sheet3").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(5, rows.Count); Assert.Equal(3, rows[0].A); Assert.Equal(3, rows[0].B); } { - var q = await MiniExcel.QueryAsync(path, sheetName: "Sheet2"); + var q = MiniExcel.QueryAsync(path, sheetName: "Sheet2").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(12, rows.Count); Assert.Equal(1, rows[0].A); Assert.Equal(1, rows[0].B); } { - var q = await MiniExcel.QueryAsync(path, sheetName: "Sheet1"); + var q = MiniExcel.QueryAsync(path, sheetName: "Sheet1").ToBlockingEnumerable(); var rows = q.ToList(); Assert.Equal(12, rows.Count); Assert.Equal(2, rows[0].A); @@ -32,32 +32,32 @@ public async Task SpecifySheetNameQueryTest() { await Assert.ThrowsAsync(async () => { - var rows = (await MiniExcel.QueryAsync(path, sheetName: "xxxx")).ToList(); + var rows = MiniExcel.QueryAsync(path, sheetName: "xxxx").ToBlockingEnumerable().ToList(); }); } await using var stream = File.OpenRead(path); { - var rows = (await stream.QueryAsync(sheetName: "Sheet3")).Cast>().ToList(); + var rows = (stream.QueryAsync(sheetName: "Sheet3").ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal(5, rows.Count); Assert.Equal(3d, rows[0]["A"]); Assert.Equal(3d, rows[0]["B"]); } { - var rows = (await stream.QueryAsync(sheetName: "Sheet2")).Cast>().ToList(); + var rows = (stream.QueryAsync(sheetName: "Sheet2").ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal(12, rows.Count); Assert.Equal(1d, rows[0]["A"]); Assert.Equal(1d, rows[0]["B"]); } { - var rows = (await stream.QueryAsync(sheetName: "Sheet1")).Cast>().ToList(); + var rows = (stream.QueryAsync(sheetName: "Sheet1").ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal(12, rows.Count); Assert.Equal(2d, rows[0]["A"]); Assert.Equal(2d, rows[0]["B"]); } { - var rows = (await stream.QueryAsync(sheetName: "Sheet1")).Cast>().ToList(); + var rows = (stream.QueryAsync(sheetName: "Sheet1").ToBlockingEnumerable()).Cast>().ToList(); Assert.Equal(12, rows.Count); Assert.Equal(2d, rows[0]["A"]); Assert.Equal(2d, rows[0]["B"]); @@ -69,9 +69,9 @@ public async Task MultiSheetsQueryBasicTest() { const string path = "../../../../../samples/xlsx/TestMultiSheet.xlsx"; await using var stream = File.OpenRead(path); - _ = await stream.QueryAsync(sheetName: "Sheet1"); - _ = await stream.QueryAsync(sheetName: "Sheet2"); - _ = await stream.QueryAsync(sheetName: "Sheet3"); + _ = stream.QueryAsync(sheetName: "Sheet1").ToBlockingEnumerable(); + _ = stream.QueryAsync(sheetName: "Sheet2").ToBlockingEnumerable(); + _ = stream.QueryAsync(sheetName: "Sheet3").ToBlockingEnumerable(); } [Fact] @@ -82,7 +82,7 @@ public async Task MultiSheetsQueryTest() var sheetNames = MiniExcel.GetSheetNames(path).ToList(); foreach (var sheetName in sheetNames) { - var rows = await MiniExcel.QueryAsync(path, sheetName: sheetName); + var rows = MiniExcel.QueryAsync(path, sheetName: sheetName).ToBlockingEnumerable(); } Assert.Equal(new[] { "Sheet1", "Sheet2", "Sheet3" }, sheetNames); } @@ -93,7 +93,7 @@ public async Task MultiSheetsQueryTest() Assert.Equal(new[] { "Sheet1", "Sheet2", "Sheet3" }, sheetNames); foreach (var sheetName in sheetNames) { - var rows = (await stream.QueryAsync(sheetName: sheetName)).ToList(); + var rows = (stream.QueryAsync(sheetName: sheetName).ToBlockingEnumerable()).ToList(); } } } diff --git a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs index a5e39b65..cf7a3972 100644 --- a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs +++ b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs @@ -30,7 +30,7 @@ public async Task DatatableTemptyRowTest() ["employees"] = employees }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); var dimension = Helpers.GetFirstSheetDimensionRefValue(path.ToString()); Assert.Equal("A1:C5", dimension); @@ -55,7 +55,7 @@ public async Task DatatableTemptyRowTest() }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); var dimension = Helpers.GetFirstSheetDimensionRefValue(path.ToString()); Assert.Equal("A1:C5", dimension); @@ -89,7 +89,7 @@ public async Task DatatableTest() ["employees"] = employees }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); var dimension = Helpers.GetFirstSheetDimensionRefValue(path.ToString()); Assert.Equal("A1:C9", dimension); @@ -112,7 +112,7 @@ public async Task DatatableTest() Assert.Equal("IT", rows[8].C); { - rows = (await MiniExcel.QueryAsync(path.ToString(), sheetName: "Sheet2")).ToList(); + rows = MiniExcel.QueryAsync(path.ToString(), sheetName: "Sheet2").ToBlockingEnumerable().ToList(); Assert.Equal(9, rows.Count); Assert.Equal("FooCompany", rows[0].A); @@ -152,7 +152,7 @@ public async Task DapperTemplateTest() await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); { - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); Assert.Equal(9, rows.Count); @@ -177,7 +177,7 @@ public async Task DapperTemplateTest() } { - var rows = (await MiniExcel.QueryAsync(path.ToString(), sheetName: "Sheet2")).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString(), sheetName: "Sheet2").ToBlockingEnumerable().ToList(); Assert.Equal(9, rows.Count); Assert.Equal("FooCompany", rows[0].A); @@ -296,7 +296,7 @@ public async Task TestGithubProject() }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); Assert.Equal("ITWeiHan Github Projects", rows[0].B); Assert.Equal("Total Star : 178", rows[8].C); @@ -451,7 +451,7 @@ public async Task TemplateAsyncBasiTest() }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); Assert.Equal("Jack", rows[1].A); Assert.Equal("2021-01-01 00:00:00", rows[1].B); Assert.Equal(true, rows[1].C); @@ -475,7 +475,7 @@ public async Task TemplateAsyncBasiTest() }; await MiniExcel.SaveAsByTemplateAsync(path, templateBytes, value); - var rows = (await MiniExcel.QueryAsync(path)).ToList(); + var rows = (MiniExcel.QueryAsync(path).ToBlockingEnumerable()).ToList(); Assert.Equal("Jack", rows[1].A); Assert.Equal("2021-01-01 00:00:00", rows[1].B); Assert.Equal(true, rows[1].C); @@ -503,7 +503,7 @@ public async Task TemplateAsyncBasiTest() await stream.SaveAsByTemplateAsync(templateBytes, value); } - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); Assert.Equal("Jack", rows[1].A); Assert.Equal("2021-01-01 00:00:00", rows[1].B); Assert.Equal(true, rows[1].C); @@ -527,7 +527,7 @@ public async Task TemplateAsyncBasiTest() }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); Assert.Equal("Jack", rows[1].A); Assert.Equal("2021-01-01 00:00:00", rows[1].B); Assert.Equal(true, rows[1].C); @@ -788,7 +788,7 @@ public async Task TemplateTest() await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); { - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); Assert.Equal(9, rows.Count); Assert.Equal("FooCompany", rows[0].A); @@ -812,7 +812,7 @@ public async Task TemplateTest() } { - var rows = (await MiniExcel.QueryAsync(path.ToString(), sheetName: "Sheet2")).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString(), sheetName: "Sheet2").ToBlockingEnumerable().ToList(); Assert.Equal(9, rows.Count); Assert.Equal("FooCompany", rows[0].A); @@ -858,7 +858,7 @@ public async Task TemplateTest() }; await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value); - var rows = (await MiniExcel.QueryAsync(path.ToString())).ToList(); + var rows = MiniExcel.QueryAsync(path.ToString()).ToBlockingEnumerable().ToList(); Assert.Equal("FooCompany", rows[0].A); Assert.Equal("Jack", rows[2].B); Assert.Equal("HR", rows[2].C); From d9d0791975ba13727e6a11a4f31881ae629b3371 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Thu, 12 Jun 2025 12:55:39 -0400 Subject: [PATCH 04/25] Decorate with ConfigureAsync(false) and remove all Task> QueryAsync(bool useHe #if NET7_0_OR_GREATER ct #endif - )) != null; rowIndex++) + ).ConfigureAwait(false)) != null; rowIndex++) { string finalRow = row; if (_config.ReadLineBreaksWithinQuotes) @@ -52,7 +52,7 @@ public async IAsyncEnumerable> QueryAsync(bool useHe #if NET7_0_OR_GREATER ct #endif - ); + ).ConfigureAwait(false); if (nextPart == null) { break; diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs index 539f34b3..7e3b0e4a 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs @@ -168,14 +168,14 @@ internal async IAsyncEnumerable> InternalQueryRangeA if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) yield break; - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) yield break; while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) continue; var headRows = new Dictionary(); @@ -193,8 +193,8 @@ internal async IAsyncEnumerable> InternalQueryRangeA if (rowIndex < startRowIndex) { - await XmlReaderHelper.ReadFirstContentAsync(reader, ct); - await XmlReaderHelper.SkipToNextSameLevelDomAsync(reader, ct); + await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false); + await XmlReaderHelper.SkipToNextSameLevelDomAsync(reader, ct).ConfigureAwait(false); continue; } if (endRowIndex.HasValue && rowIndex > endRowIndex.Value) @@ -216,7 +216,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA } // row -> c, must after `if (nextRowIndex < rowIndex)` condition code, eg. The first empty row has no xml element,and the second row xml element is - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct) && !_config.IgnoreEmptyRows) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false) && !_config.IgnoreEmptyRows) { //Fill in case of self closed empty row tag eg. yield return GetCell(useHeaderRow, maxColumnIndex, headRows, startColumnIndex); @@ -283,13 +283,13 @@ internal async IAsyncEnumerable> InternalQueryRangeA yield return cell; } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } } } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } diff --git a/src/MiniExcel/Utils/XmlReaderHelper.cs b/src/MiniExcel/Utils/XmlReaderHelper.cs index 357f0678..3116d2d0 100644 --- a/src/MiniExcel/Utils/XmlReaderHelper.cs +++ b/src/MiniExcel/Utils/XmlReaderHelper.cs @@ -118,10 +118,10 @@ public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream { if (IsStartElement(reader, "si", nss)) { - var value = StringHelper.ReadStringItem(reader); + var value = await StringHelper.ReadStringItemAsync(reader, ct).ConfigureAwait(false); yield return value; } - else if (!await SkipContentAsync(reader, ct)) + else if (!await SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } From 7e2049ad40f06d17d684c7fced1ae5e721eb542e Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Thu, 12 Jun 2025 14:37:22 -0400 Subject: [PATCH 05/25] Fix source generation for ConfigureAwait after #endif --- src/MiniExcel/MiniExcelLibs.csproj | 2 +- src/MiniExcel/Utils/StringHelper.cs | 4 ++-- src/MiniExcel/Utils/XmlReaderHelper.cs | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj index 36afb04f..faea11fd 100644 --- a/src/MiniExcel/MiniExcelLibs.csproj +++ b/src/MiniExcel/MiniExcelLibs.csproj @@ -56,7 +56,7 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/MiniExcel/Utils/StringHelper.cs b/src/MiniExcel/Utils/StringHelper.cs index d8d2d6c5..067f5a5d 100644 --- a/src/MiniExcel/Utils/StringHelper.cs +++ b/src/MiniExcel/Utils/StringHelper.cs @@ -34,7 +34,7 @@ public static async Task ReadStringItemAsync(XmlReader reader, Cancellat #if NET6_0_OR_GREATER .WaitAsync(ct) #endif - ); + .ConfigureAwait(false)); } else if (XmlReaderHelper.IsStartElement(reader, "r", _ns)) { @@ -67,7 +67,7 @@ private static async Task ReadRichTextRunAsync(XmlReader reader, Cancell #if NET6_0_OR_GREATER .WaitAsync(ct) #endif -); + .ConfigureAwait(false)); } else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) { diff --git a/src/MiniExcel/Utils/XmlReaderHelper.cs b/src/MiniExcel/Utils/XmlReaderHelper.cs index 3116d2d0..71071b2e 100644 --- a/src/MiniExcel/Utils/XmlReaderHelper.cs +++ b/src/MiniExcel/Utils/XmlReaderHelper.cs @@ -20,12 +20,12 @@ await reader.MoveToContentAsync() #if NET6_0_OR_GREATER .WaitAsync(ct) #endif -; + .ConfigureAwait(false); await reader.ReadAsync() #if NET6_0_OR_GREATER .WaitAsync(ct) #endif -; + .ConfigureAwait(false); } /// @@ -52,7 +52,7 @@ await reader.ReadAsync() #if NET6_0_OR_GREATER .WaitAsync(ct) #endif -; + .ConfigureAwait(false); return false; } @@ -60,12 +60,12 @@ await reader.MoveToContentAsync() #if NET6_0_OR_GREATER .WaitAsync(ct) #endif - ; + .ConfigureAwait(false); await reader.ReadAsync() #if NET6_0_OR_GREATER .WaitAsync(ct) #endif - ; + .ConfigureAwait(false); return true; } @@ -79,7 +79,7 @@ await reader.ReadAsync() #if NET6_0_OR_GREATER .WaitAsync(ct) #endif -; + .ConfigureAwait(false); return false; } @@ -87,7 +87,7 @@ await reader.SkipAsync() #if NET6_0_OR_GREATER .WaitAsync(ct) #endif - ; + .ConfigureAwait(false); return true; } From 38d460ae3ba5c450313231dca9cc41d8af0a5c99 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Thu, 12 Jun 2025 23:01:08 -0400 Subject: [PATCH 06/25] Add ConfigureAwait where missed --- src/MiniExcel/Utils/XmlReaderHelper.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/MiniExcel/Utils/XmlReaderHelper.cs b/src/MiniExcel/Utils/XmlReaderHelper.cs index 71071b2e..c660c28d 100644 --- a/src/MiniExcel/Utils/XmlReaderHelper.cs +++ b/src/MiniExcel/Utils/XmlReaderHelper.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using System.Xml; @@ -14,7 +15,7 @@ internal static partial class XmlReaderHelper /// /// [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task PassXmlDeclarationAndWorksheet(this XmlReader reader, CancellationToken ct = default) + public static async Task PassXmlDeclarationAndWorksheetAsync(this XmlReader reader, CancellationToken ct = default) { await reader.MoveToContentAsync() #if NET6_0_OR_GREATER @@ -104,14 +105,14 @@ public static string GetAttribute(XmlReader reader, string name, params string[] } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream, CancellationToken ct = default, params string[] nss) + public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream, [EnumeratorCancellation]CancellationToken ct = default, params string[] nss) { using (var reader = XmlReader.Create(stream)) { if (!IsStartElement(reader, "sst", nss)) yield break; - if (!await ReadFirstContentAsync(reader, ct)) + if (!await ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) yield break; while (!reader.EOF) From 295b691a60a8097e033af1eaefde78086513ab06 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Fri, 13 Jun 2025 08:44:16 -0400 Subject: [PATCH 07/25] Convert everything in ExcelOpenXmlSheetReader to Async --- .../OpenXml/ExcelOpenXmlSheetReader.cs | 263 +++++++++++++----- 1 file changed, 194 insertions(+), 69 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs index 7e3b0e4a..7344872d 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs @@ -27,8 +27,6 @@ internal partial class ExcelOpenXmlSheetReader : IExcelReader internal readonly ExcelOpenXmlZip _archive; private readonly OpenXmlConfiguration _config; - private static readonly XmlReaderSettings _xmlSettings = GetXmlReaderSettings(false); - public ExcelOpenXmlSheetReader(Stream stream, IConfiguration configuration, bool isUpdateMode = true) { _archive = new ExcelOpenXmlZip(stream); @@ -131,6 +129,7 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea return QueryImplAsync(QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async IAsyncEnumerable> InternalQueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, [EnumeratorCancellation] CancellationToken ct = default) { @@ -147,16 +146,24 @@ internal async IAsyncEnumerable> InternalQueryRangeA // TODO: need to optimize performance // Q. why need 3 times openstream merge one open read? A. no, zipstream can't use position = 0 - if (_config.FillMergedCells && !TryGetMergeCells(sheetEntry, out _mergeCells)) + var mergeCellsResult = await TryGetMergeCellsAsync(sheetEntry, ct).ConfigureAwait(false); + if (_config.FillMergedCells && !mergeCellsResult.IsSuccess) { yield break; } - if (!TryGetMaxRowColumnIndex(sheetEntry, out var withoutCR, out var maxRowIndex, out var maxColumnIndex)) + _mergeCells = mergeCellsResult.MergeCells; + + var maxRowColumnIndexResult = await TryGetMaxRowColumnIndexAsync(sheetEntry, ct).ConfigureAwait(false); + if (!maxRowColumnIndexResult.IsSuccess) { yield break; } + var maxRowIndex = maxRowColumnIndexResult.MaxRowIndex; + var maxColumnIndex = maxRowColumnIndexResult.MaxColumnIndex; + var withoutCR = maxRowColumnIndexResult.WithoutCR; + if (endColumnIndex.HasValue) { maxColumnIndex = endColumnIndex.Value; @@ -234,8 +241,11 @@ internal async IAsyncEnumerable> InternalQueryRangeA var aS = reader.GetAttribute("s"); var aR = reader.GetAttribute("r"); var aT = reader.GetAttribute("t"); - var cellValue = ReadCellAndSetColumnIndex(reader, ref columnIndex, withoutCR, - startColumnIndex, aR, aT); + var cellAndColumn = await ReadCellAndSetColumnIndexAsync(reader, columnIndex, withoutCR, + startColumnIndex, aR, aT, ct).ConfigureAwait(false); + + var cellValue = cellAndColumn.CellValue; + columnIndex = cellAndColumn.ColumnIndex; if (_config.FillMergedCells) { @@ -366,7 +376,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA yield return v; } } - + private ZipArchiveEntry GetSheetEntry(string sheetName) { // if sheets count > 1 need to read xl/_rels/workbook.xml.rels @@ -440,7 +450,8 @@ private static XmlReaderSettings GetXmlReaderSettings(bool async) }; } - private void SetSharedStrings() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task SetSharedStringsAsync(CancellationToken ct = default) { if (_sharedStrings != null) return; @@ -453,12 +464,17 @@ private void SetSharedStrings() if (_config.EnableSharedStringCache && sharedStringsEntry.Length >= _config.SharedStringCacheSize) { _sharedStrings = new SharedStringsDiskCache(); - foreach (var sharedString in XmlReaderHelper.GetSharedStrings(stream, _ns)) + await foreach (var sharedString in XmlReaderHelper.GetSharedStringsAsync(stream, ct, _ns).WithCancellation(ct).ConfigureAwait(false)) _sharedStrings[idx++] = sharedString; } else if (_sharedStrings == null) { - _sharedStrings = XmlReaderHelper.GetSharedStrings(stream, _ns).ToDictionary((x) => idx++, x => x); + var list = new List(); + await foreach (var str in XmlReaderHelper.GetSharedStringsAsync(stream, ct, _ns).WithCancellation(ct).ConfigureAwait(false)) + { + list.Add(str); + } + _sharedStrings = list.ToDictionary((x) => idx++, x => x); } } } @@ -470,15 +486,25 @@ private void SetWorkbookRels(ReadOnlyCollection entries) _sheetRecords = GetWorkbookRels(entries); } - internal static IEnumerable ReadWorkbook(ReadOnlyCollection entries) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCollection entries, [EnumeratorCancellation] CancellationToken ct = default) { + var xmlSettings = GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + + using (var stream = entries.Single(w => w.FullName == "xl/workbook.xml").Open()) - using (var reader = XmlReader.Create(stream, _xmlSettings)) + using (var reader = XmlReader.Create(stream, xmlSettings)) { if (!XmlReaderHelper.IsStartElement(reader, "workbook", _ns)) yield break; - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) yield break; var activeSheetIndex = 0; @@ -486,7 +512,7 @@ internal static IEnumerable ReadWorkbook(ReadOnlyCollection ReadWorkbook(ReadOnlyCollection ReadWorkbook(ReadOnlyCollection ReadWorkbook(ReadOnlyCollection ReadWorkbook(ReadOnlyCollection GetWorkbookRels(ReadOnlyCollection entries) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal async Task> GetWorkbookRelsAsync(ReadOnlyCollection entries, CancellationToken ct = default) { - var sheetRecords = ReadWorkbook(entries).ToList(); + var xmlSettings = GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + + var sheetRecords = new List(); + await foreach (var sheetRecord in ReadWorkbookAsync(entries, ct).WithCancellation(ct).ConfigureAwait(false)) + { + sheetRecords.Add(sheetRecord); + } using (var stream = entries.Single(w => w.FullName == "xl/_rels/workbook.xml.rels").Open()) - using (var reader = XmlReader.Create(stream, _xmlSettings)) + using (var reader = XmlReader.Create(stream, xmlSettings)) { if (!XmlReaderHelper.IsStartElement(reader, "Relationships", "http://schemas.openxmlformats.org/package/2006/relationships")) return null; - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) return null; while (!reader.EOF) @@ -568,9 +607,13 @@ internal List GetWorkbookRels(ReadOnlyCollection e } } - reader.Skip(); + await reader.SkipAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif + ; } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } @@ -580,7 +623,20 @@ internal List GetWorkbookRels(ReadOnlyCollection e return sheetRecords; } - private object ReadCellAndSetColumnIndex(XmlReader reader, ref int columnIndex, bool withoutCR, int startColumnIndex, string aR, string aT) + internal class CellAndColumn + { + public object CellValue { get; } + public int ColumnIndex { get; } = -1; + + public CellAndColumn(object cellValue, int columnIndex) + { + CellValue = cellValue; + ColumnIndex = columnIndex; + } + } + + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task ReadCellAndSetColumnIndexAsync(XmlReader reader, int columnIndex, bool withoutCR, int startColumnIndex, string aR, string aT, CancellationToken ct = default) { const int xfIndex = -1; int newColumnIndex; @@ -598,18 +654,18 @@ private object ReadCellAndSetColumnIndex(XmlReader reader, ref int columnIndex, if (columnIndex < startColumnIndex) { - if (!XmlReaderHelper.ReadFirstContent(reader)) - return null; + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + return new CellAndColumn(null, columnIndex); while (!reader.EOF) - if (!XmlReaderHelper.SkipContent(reader)) + if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) break; - return null; + return new CellAndColumn(null, columnIndex); } - if (!XmlReaderHelper.ReadFirstContent(reader)) - return null; + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + return new CellAndColumn(null, columnIndex); object value = null; while (!reader.EOF) @@ -626,13 +682,13 @@ private object ReadCellAndSetColumnIndex(XmlReader reader, ref int columnIndex, if (!string.IsNullOrEmpty(rawValue)) ConvertCellValue(rawValue, aT, xfIndex, out value); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } } - return value; + return new CellAndColumn(value, columnIndex); } private void ConvertCellValue(string rawValue, string aT, int xfIndex, out object value) @@ -716,8 +772,17 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec } } - internal IList GetDimensions() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal async Task> GetDimensionsAsync(CancellationToken ct = default) { + var xmlSettings = GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + var ranges = new List(); var sheets = _archive.entries.Where(e => @@ -735,9 +800,9 @@ internal IList GetDimensions() var withoutCR = false; using (var sheetStream = sheet.Open()) - using (var reader = XmlReader.Create(sheetStream, _xmlSettings)) + using (var reader = XmlReader.Create(sheetStream, xmlSettings)) { - while (reader.Read()) + while (await reader.ReadAsync().ConfigureAwait(false)) { if (XmlReaderHelper.IsStartElement(reader, "c", _ns)) { @@ -783,19 +848,19 @@ internal IList GetDimensions() if (withoutCR) { using (var sheetStream = sheet.Open()) - using (var reader = XmlReader.Create(sheetStream, _xmlSettings)) + using (var reader = XmlReader.Create(sheetStream, xmlSettings)) { if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) throw new InvalidDataException("No worksheet data found for the sheet"); - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) throw new InvalidOperationException("Excel sheet does not contain any data"); while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) continue; while (!reader.EOF) @@ -804,7 +869,7 @@ internal IList GetDimensions() { maxRowIndex++; - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) continue; var cellIndex = -1; @@ -816,17 +881,17 @@ internal IList GetDimensions() maxColumnIndex = Math.Max(maxColumnIndex, cellIndex); } - if (!XmlReaderHelper.SkipContent(reader)) + if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) break; } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } @@ -845,15 +910,50 @@ internal IList GetDimensions() return ranges; } - internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out bool withoutCR, out int maxRowIndex, out int maxColumnIndex) + internal class GetMaxRowColumnIndexResult + { + public bool IsSuccess { get; } + public bool WithoutCR { get; } + public int MaxRowIndex { get; } = -1; + public int MaxColumnIndex { get; } = -1; + + public GetMaxRowColumnIndexResult(bool isSuccess) + { + IsSuccess = isSuccess; + } + + + public GetMaxRowColumnIndexResult(bool isSuccess, bool withoutCR, int maxRowIndex, int maxColumnIndex) + : this(isSuccess) + { + WithoutCR = withoutCR; + MaxRowIndex = maxRowIndex; + MaxColumnIndex = maxColumnIndex; + } + } + + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal static async Task TryGetMaxRowColumnIndexAsync(ZipArchiveEntry sheetEntry, CancellationToken ct = default) { - withoutCR = false; - maxRowIndex = -1; - maxColumnIndex = -1; + var xmlSettings = GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + + bool withoutCR = false; + int maxRowIndex = -1; + int maxColumnIndex = -1; using (var sheetStream = sheetEntry.Open()) - using (var reader = XmlReader.Create(sheetStream, _xmlSettings)) + using (var reader = XmlReader.Create(sheetStream, xmlSettings)) { - while (reader.Read()) + while (await reader.ReadAsync() +#if NET6_0_OR_GREATER + .WaitAsync(ct) +#endif + .ConfigureAwait(false)) { if (XmlReaderHelper.IsStartElement(reader, "c", _ns)) { @@ -897,19 +997,19 @@ internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out boo if (withoutCR) { using (var sheetStream = sheetEntry.Open()) - using (var reader = XmlReader.Create(sheetStream, _xmlSettings)) + using (var reader = XmlReader.Create(sheetStream, xmlSettings)) { if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) - return false; + return new GetMaxRowColumnIndexResult(false); - if (!XmlReaderHelper.ReadFirstContent(reader)) - return false; + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + return new GetMaxRowColumnIndexResult(false); while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) continue; while (!reader.EOF) @@ -918,7 +1018,7 @@ internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out boo { maxRowIndex++; - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) continue; // Cells @@ -931,17 +1031,17 @@ internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out boo maxColumnIndex = Math.Max(maxColumnIndex, cellIndex); } - if (!XmlReaderHelper.SkipContent(reader)) + if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) break; } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } @@ -949,26 +1049,51 @@ internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out boo } } - return true; + return new GetMaxRowColumnIndexResult(true, withoutCR, maxRowIndex, maxColumnIndex); + } + + internal class MergeCellsResult + { + public bool IsSuccess { get; } + public MergeCells MergeCells { get; } + + public MergeCellsResult(bool isSuccess) + { + IsSuccess = isSuccess; + } + + public MergeCellsResult(bool isSuccess, MergeCells mergeCells) + : this (isSuccess) + { + MergeCells = mergeCells; + } } - internal static bool TryGetMergeCells(ZipArchiveEntry sheetEntry, out MergeCells mergeCells) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal static async Task TryGetMergeCellsAsync(ZipArchiveEntry sheetEntry, CancellationToken ct = default) { - mergeCells = new MergeCells(); + var xmlSettings = GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + var mergeCells = new MergeCells(); using (var sheetStream = sheetEntry.Open()) - using (XmlReader reader = XmlReader.Create(sheetStream, _xmlSettings)) + using (XmlReader reader = XmlReader.Create(sheetStream, xmlSettings)) { if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) - return false; - while (reader.Read()) + return new MergeCellsResult(false); + while (await reader.ReadAsync().ConfigureAwait(false)) { if (!XmlReaderHelper.IsStartElement(reader, "mergeCells", _ns)) { continue; } - if (!XmlReaderHelper.ReadFirstContent(reader)) - return false; + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + return new MergeCellsResult(false); while (!reader.EOF) { @@ -996,15 +1121,15 @@ internal static bool TryGetMergeCells(ZipArchiveEntry sheetEntry, out MergeCells } } - XmlReaderHelper.SkipContent(reader); + await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) { break; } } } - return true; + return new MergeCellsResult(true, mergeCells); } } From 20e74d3650b4226ae882d2dc9c2d60e757642798 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Fri, 13 Jun 2025 22:22:16 -0400 Subject: [PATCH 08/25] Convert a bunch of stuff to Async --- src/MiniExcel/IExcelTemplate.cs | 16 +- src/MiniExcel/IExcelWriter.cs | 6 +- src/MiniExcel/MiniExcel.Async.cs | 51 +------ src/MiniExcel/MiniExcel.cs | 45 +++--- src/MiniExcel/MiniExcelLibs.csproj | 5 +- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 10 +- .../OpenXml/ExcelOpenXmlSheetWriter.cs | 85 ----------- .../ExcelOpenXmlTemplate.Impl.cs | 137 +++++++++++++++--- .../ExcelOpenXmlTemplate.MergeCells.cs | 31 ++-- .../SaveByTemplate/ExcelOpenXmlTemplate.cs | 41 +++--- src/MiniExcel/Utils/calChainHelper.cs | 9 +- .../MiniExcelTemplateAsyncTests.cs | 2 +- 12 files changed, 204 insertions(+), 234 deletions(-) diff --git a/src/MiniExcel/IExcelTemplate.cs b/src/MiniExcel/IExcelTemplate.cs index d4a66c55..6436dc46 100644 --- a/src/MiniExcel/IExcelTemplate.cs +++ b/src/MiniExcel/IExcelTemplate.cs @@ -3,19 +3,15 @@ namespace MiniExcelLibs { - internal interface IExcelTemplate - { - void SaveAsByTemplate(string templatePath, object value); - void SaveAsByTemplate(byte[] templateBtyes, object value); - void MergeSameCells(string path); - void MergeSameCells(byte[] fileInBytes); - } - - internal interface IExcelTemplateAsync : IExcelTemplate + internal partial interface IExcelTemplateAsync { + [Zomp.SyncMethodGenerator.CreateSyncVersion] Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken cancellationToken = default(CancellationToken)); - Task SaveAsByTemplateAsync(byte[] templateBtyes, object value, CancellationToken cancellationToken = default(CancellationToken)); + [Zomp.SyncMethodGenerator.CreateSyncVersion] + Task SaveAsByTemplateAsync(byte[] templateBytes, object value, CancellationToken cancellationToken = default(CancellationToken)); + [Zomp.SyncMethodGenerator.CreateSyncVersion] Task MergeSameCellsAsync(string path, CancellationToken cancellationToken = default(CancellationToken)); + [Zomp.SyncMethodGenerator.CreateSyncVersion] Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken cancellationToken = default(CancellationToken)); } } diff --git a/src/MiniExcel/IExcelWriter.cs b/src/MiniExcel/IExcelWriter.cs index feea4171..74928dd2 100644 --- a/src/MiniExcel/IExcelWriter.cs +++ b/src/MiniExcel/IExcelWriter.cs @@ -3,11 +3,11 @@ namespace MiniExcelLibs { - internal interface IExcelWriter + internal partial interface IExcelWriter { - int[] SaveAs(); + [Zomp.SyncMethodGenerator.CreateSyncVersion] Task SaveAsAsync(CancellationToken cancellationToken = default); - int Insert(bool overwriteSheet = false); + [Zomp.SyncMethodGenerator.CreateSyncVersion] Task InsertAsync(bool overwriteSheet = false, CancellationToken cancellationToken = default); } } diff --git a/src/MiniExcel/MiniExcel.Async.cs b/src/MiniExcel/MiniExcel.Async.cs index a844a170..85eaa2ae 100644 --- a/src/MiniExcel/MiniExcel.Async.cs +++ b/src/MiniExcel/MiniExcel.Async.cs @@ -20,7 +20,7 @@ public static async Task InsertAsync(string path, object value, string shee if (!File.Exists(path)) { - var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, cancellationToken: cancellationToken); + var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, ct: cancellationToken); return rowsWritten.FirstOrDefault(); } @@ -52,55 +52,6 @@ public static async TaskInsertAsync(this Stream stream, object value, strin } } - public static async Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false, CancellationToken cancellationToken = default) - { - if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm") - throw new NotSupportedException("MiniExcel's SaveAs does not support the .xlsm format"); - - using (var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew)) - return await SaveAsAsync(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, cancellationToken); - } - - public static async Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(cancellationToken); - } - - public static async Task MergeSameCellsAsync(string mergedFilePath, string path, ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - await Task.Run(() => MergeSameCells(mergedFilePath, path, excelType, configuration), cancellationToken).ConfigureAwait(false); - } - - public static async Task MergeSameCellsAsync(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, cancellationToken); - } - - public static async Task MergeSameCellsAsync(this Stream stream, byte[] fileBytes, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(fileBytes, cancellationToken); - } - - public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, cancellationToken).ConfigureAwait(false); - } - - public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, cancellationToken).ConfigureAwait(false); - } - - public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - await Task.Run(() => SaveAsByTemplate(path, templatePath, value, configuration), cancellationToken).ConfigureAwait(false); - } - - public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - await Task.Run(() => SaveAsByTemplate(path, templateBytes, value, configuration), cancellationToken).ConfigureAwait(false); - } - /// /// QueryAsDataTable is not recommended, because it'll load all data into memory. /// diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index 71a73856..c9d69d0f 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -78,18 +78,20 @@ public static int Insert(this Stream stream, object value, string sheetName = "S } } - public static int[] SaveAs(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false, CancellationToken ct = default) { if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm") throw new NotSupportedException("MiniExcel's SaveAs does not support the .xlsm format"); using (var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew)) - return SaveAs(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration); + return await SaveAsAsync(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, ct).ConfigureAwait(false); } - public static int[] SaveAs(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) { - return ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAs(); + return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(ct).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -174,44 +176,51 @@ public static IEnumerable QueryRange(this Stream stream, bool useHeader #endregion QueryRange - public static void SaveAsByTemplate(string path, string templatePath, object value, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value, IConfiguration configuration = null, CancellationToken ct = default) { using (var stream = File.Create(path)) - SaveAsByTemplate(stream, templatePath, value, configuration); + await SaveAsByTemplateAsync(stream, templatePath, value, configuration, ct); } - public static void SaveAsByTemplate(string path, byte[] templateBytes, object value, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken ct = default) { using (var stream = File.Create(path)) - SaveAsByTemplate(stream, templateBytes, value, configuration); + await SaveAsByTemplateAsync(stream, templateBytes, value, configuration, ct); } - public static void SaveAsByTemplate(this Stream stream, string templatePath, object value, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken ct = default) { - ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templatePath, value); + await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, ct); } - public static void SaveAsByTemplate(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken ct = default) { - ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templateBytes, value); + await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, ct); } #region MergeCells - public static void MergeSameCells(string mergedFilePath, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task MergeSameCellsAsync(string mergedFilePath, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) { using (var stream = File.Create(mergedFilePath)) - MergeSameCells(stream, path, excelType, configuration); + await MergeSameCellsAsync(stream, path, excelType, configuration, ct).ConfigureAwait(false); } - public static void MergeSameCells(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task MergeSameCellsAsync(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) { - ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(path); + await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, ct).ConfigureAwait(false); } - public static void MergeSameCells(this Stream stream, byte[] filePath, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task MergeSameCellsAsync(this Stream stream, byte[] filePath, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) { - ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(filePath); + await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(filePath, ct).ConfigureAwait(false); } #endregion diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj index faea11fd..f40c18ac 100644 --- a/src/MiniExcel/MiniExcelLibs.csproj +++ b/src/MiniExcel/MiniExcelLibs.csproj @@ -56,9 +56,6 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 85633cbf..3e1e4561 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -17,11 +17,12 @@ namespace MiniExcelLibs.OpenXml { internal partial class ExcelOpenXmlSheetWriter : IExcelWriter { + [Zomp.SyncMethodGenerator.CreateSyncVersion] public async Task SaveAsAsync(CancellationToken cancellationToken = default) { try { - await GenerateDefaultOpenXmlAsync(cancellationToken); + await GenerateDefaultOpenXmlAsync(cancellationToken).ConfigureAwait(false); var sheets = GetSheets(); var rowsWritten = new List(); @@ -32,11 +33,11 @@ public async Task SaveAsAsync(CancellationToken cancellationToken = defau _sheets.Add(sheet.Item1); //TODO:remove _currentSheetIndex = sheet.Item1.SheetIdx; - var rows = await CreateSheetXmlAsync(sheet.Item2, sheet.Item1.Path, cancellationToken); + var rows = await CreateSheetXmlAsync(sheet.Item2, sheet.Item1.Path, cancellationToken).ConfigureAwait(false); rowsWritten.Add(rows); } - await GenerateEndXmlAsync(cancellationToken); + await GenerateEndXmlAsync(cancellationToken).ConfigureAwait(false); return rowsWritten.ToArray(); } finally @@ -45,6 +46,7 @@ public async Task SaveAsAsync(CancellationToken cancellationToken = defau } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] public async Task InsertAsync(bool overwriteSheet = false, CancellationToken cancellationToken = default) { try @@ -54,7 +56,7 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke cancellationToken.ThrowIfCancellationRequested(); - var sheetRecords = new ExcelOpenXmlSheetReader(_stream, _configuration).GetWorkbookRels(_archive.Entries).ToArray(); + var sheetRecords = (await new ExcelOpenXmlSheetReader(_stream, _configuration).GetWorkbookRelsAsync(_archive.Entries, cancellationToken).ConfigureAwait(false)).ToArray(); foreach (var sheetRecord in sheetRecords.OrderBy(o => o.Id)) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index 7f069f55..343848e7 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -45,91 +45,6 @@ public ExcelOpenXmlSheetWriter(Stream stream, object value, string sheetName, IC _defaultSheetName = sheetName; } - public int[] SaveAs() - { - GenerateDefaultOpenXml(); - - var sheets = GetSheets(); - var rowsWritten = new List(); - - foreach (var sheet in sheets) - { - _sheets.Add(sheet.Item1); //TODO:remove - _currentSheetIndex = sheet.Item1.SheetIdx; - var rows = CreateSheetXml(sheet.Item2, sheet.Item1.Path); - rowsWritten.Add(rows); - } - - GenerateEndXml(); - _archive.Dispose(); - - return rowsWritten.ToArray(); - } - - public int Insert(bool overwriteSheet = false) - { - if (!_configuration.FastMode) - { - throw new InvalidOperationException("Insert requires fast mode to be enabled"); - } - - var sheetRecords = new ExcelOpenXmlSheetReader(_stream, _configuration).GetWorkbookRels(_archive.Entries).ToArray(); - foreach (var sheetRecord in sheetRecords.OrderBy(o => o.Id)) - { - _sheets.Add(new SheetDto { Name = sheetRecord.Name, SheetIdx = (int)sheetRecord.Id, State = sheetRecord.State }); - } - var existSheetDto = _sheets.SingleOrDefault(s => s.Name == _defaultSheetName); - if (existSheetDto != null && !overwriteSheet) - { - throw new Exception($"Sheet “{_defaultSheetName}” already exist"); - } - - GenerateStylesXml();//GenerateStylesXml必须在校验overwriteSheet之后,避免不必要的样式更改 - int rowsWritten; - if (existSheetDto == null) - { - _currentSheetIndex = (int)sheetRecords.Max(m => m.Id) + 1; - var insertSheetInfo = GetSheetInfos(_defaultSheetName); - var insertSheetDto = insertSheetInfo.ToDto(_currentSheetIndex); - _sheets.Add(insertSheetDto); - rowsWritten = CreateSheetXml(_value, insertSheetDto.Path); - } - else - { - _currentSheetIndex = existSheetDto.SheetIdx; - _archive.Entries.Single(s => s.FullName == existSheetDto.Path).Delete(); - rowsWritten = CreateSheetXml(_value, existSheetDto.Path); - } - - AddFilesToZip(); - - _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(_currentSheetIndex - 1))?.Delete(); - GenerateDrawinRelXml(_currentSheetIndex - 1); - - _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(_currentSheetIndex - 1))?.Delete(); - GenerateDrawingXml(_currentSheetIndex - 1); - - GenerateWorkBookXmls(out StringBuilder workbookXml, out StringBuilder workbookRelsXml, out Dictionary sheetsRelsXml); - foreach (var sheetRelsXml in sheetsRelsXml) - { - var sheetRelsXmlPath = ExcelFileNames.SheetRels(sheetRelsXml.Key); - _archive.Entries.SingleOrDefault(s => s.FullName == sheetRelsXmlPath)?.Delete(); - CreateZipEntry(sheetRelsXmlPath, null, ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value)); - } - - _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Workbook)?.Delete(); - CreateZipEntry(ExcelFileNames.Workbook, ExcelContentTypes.Workbook, ExcelXml.DefaultWorkbookXml.Replace("{{sheets}}", workbookXml.ToString())); - - _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels)?.Delete(); - CreateZipEntry(ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString())); - - InsertContentTypesXml(); - - _archive.Dispose(); - - return rowsWritten; - } - internal void GenerateDefaultOpenXml() { CreateZipEntry(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels); diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs index 68b1a094..dd884cce 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs @@ -11,6 +11,8 @@ using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; using System.Xml; namespace MiniExcelLibs.OpenXml.SaveByTemplate @@ -146,7 +148,8 @@ internal partial class ExcelOpenXmlTemplate private static readonly Regex _nonTemplateRegex = new Regex(@".*?\{\{.*?\}\}.*?", RegexOptions.Compiled); #endif - private void GenerateSheetXmlImplByUpdateMode(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, IDictionary inputMaps, IDictionary sharedStrings, bool mergeCells = false) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task GenerateSheetXmlImplByUpdateModeAsync(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, IDictionary inputMaps, IDictionary sharedStrings, bool mergeCells = false, CancellationToken ct = default) { var doc = new XmlDocument(); doc.Load(sheetStream); @@ -163,7 +166,7 @@ private void GenerateSheetXmlImplByUpdateMode(ZipArchiveEntry sheetZipEntry, Str GetMergeCells(doc, worksheet); UpdateDimensionAndGetRowsInfo(inputMaps, doc, rows, !mergeCells); - WriteSheetXml(stream, doc, sheetData, mergeCells); + await WriteSheetXmlAsync(stream, doc, sheetData, mergeCells, ct).ConfigureAwait(false); } @@ -294,7 +297,8 @@ private class ConditionalFormatRange public List Ranges { get; set; } } - private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode sheetData, bool mergeCells = false) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task WriteSheetXmlAsync(Stream outputFileStream, XmlDocument doc, XmlNode sheetData, bool mergeCells = false, CancellationToken ct = default) { //Q.Why so complex? //A.Because try to use string stream avoid OOM when rendering rows @@ -328,8 +332,16 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she using (var writer = new StreamWriter(outputFileStream, Encoding.UTF8)) { - writer.Write(contents[0]); - writer.Write($"<{prefix}sheetData>"); // prefix problem + await writer.WriteAsync(contents[0] +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); + await writer.WriteAsync($"<{prefix}sheetData>" +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); // prefix problem if (mergeCells) { @@ -453,7 +465,27 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she var iEnumerableIndex = 0; enumrowstart = newRowIndex; - GenerateCellValues(endPrefix, writer, ref rowIndexDiff, rowXml, ref headerDiff, ref prevHeader, mergeRowCount, isHeaderRow, ref currentHeader, rowInfo, row, groupingRowDiff, ref newRowIndex, innerXml, outerXmlOpen, ref isFirst, ref iEnumerableIndex, row); + var generateCellValuesContext = new GenerateCellValuesContext() + { + currentHeader = currentHeader, + headerDiff = headerDiff, + iEnumerableIndex = iEnumerableIndex, + isFirst = isFirst, + newRowIndex = newRowIndex, + prevHeader = prevHeader, + rowIndexDiff = rowIndexDiff, + }; + + generateCellValuesContext = await GenerateCellValuesAsync(generateCellValuesContext, endPrefix, writer, rowXml, mergeRowCount, isHeaderRow, rowInfo, row, groupingRowDiff, innerXml, outerXmlOpen, row, ct).ConfigureAwait(false); + + rowIndexDiff = generateCellValuesContext.rowIndexDiff; + headerDiff = generateCellValuesContext.headerDiff; + prevHeader = generateCellValuesContext.prevHeader; + newRowIndex = generateCellValuesContext.newRowIndex; + isFirst = generateCellValuesContext.isFirst; + iEnumerableIndex = generateCellValuesContext.iEnumerableIndex; + currentHeader = generateCellValuesContext.currentHeader; + enumrowend = newRowIndex - 1; var conditionalFormats = conditionalFormatRanges.Where(cfr => cfr.Ranges.Any(r => r.ContainsRow(originRowIndex))); @@ -512,38 +544,86 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she #endregion - writer.Write($""); + await writer.WriteAsync($"" +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); if (_newXMergeCellInfos.Count != 0) { - writer.Write($"<{prefix}mergeCells count=\"{_newXMergeCellInfos.Count}\">"); + await writer.WriteAsync($"<{prefix}mergeCells count=\"{_newXMergeCellInfos.Count}\">" +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); foreach (var cell in _newXMergeCellInfos) { - writer.Write(cell.ToXmlString(prefix)); + await writer.WriteAsync(cell.ToXmlString(prefix) +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); } - writer.Write($""); + await writer.WriteLineAsync($"" +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); } if (!string.IsNullOrEmpty(phoneticPrXml)) { - writer.Write(phoneticPrXml); + await writer.WriteAsync(phoneticPrXml +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); } if (newConditionalFormatRanges.Count != 0) { - writer.Write(string.Join(string.Empty, newConditionalFormatRanges.Select(cf => cf.Node.OuterXml))); + await writer.WriteAsync(string.Join(string.Empty, newConditionalFormatRanges.Select(cf => cf.Node.OuterXml)) +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); } - writer.Write(contents[1]); + await writer.WriteAsync(contents[1] +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); } } + class GenerateCellValuesContext + { + public int rowIndexDiff { get; set; } + public int headerDiff { get; set; } + public string prevHeader { get; set; } + public string currentHeader { get; set; } + public int newRowIndex { get; set; } + public bool isFirst { get; set; } + public int iEnumerableIndex { get; set; } + } + //todo: refactor in a way that needs less parameters - private void GenerateCellValues(string endPrefix, StreamWriter writer, ref int rowIndexDiff, - StringBuilder rowXml, ref int headerDiff, ref string prevHeader, int mergeRowCount, bool isHeaderRow, - ref string currentHeader, XRowInfo rowInfo, XmlElement row, int groupingRowDiff, ref int newRowIndex, - string innerXml, StringBuilder outerXmlOpen, ref bool isFirst, ref int iEnumerableIndex, XmlElement rowElement) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task GenerateCellValuesAsync(GenerateCellValuesContext generateCellValuesContext, string endPrefix, StreamWriter writer, + StringBuilder rowXml, int mergeRowCount, bool isHeaderRow, + XRowInfo rowInfo, XmlElement row, int groupingRowDiff, + string innerXml, StringBuilder outerXmlOpen, XmlElement rowElement, CancellationToken ct = default) { + var rowIndexDiff = generateCellValuesContext.rowIndexDiff; + var headerDiff = generateCellValuesContext.headerDiff; + var prevHeader = generateCellValuesContext.prevHeader; + var newRowIndex = generateCellValuesContext.newRowIndex; + var isFirst = generateCellValuesContext.isFirst; + var iEnumerableIndex = generateCellValuesContext.iEnumerableIndex; + var currentHeader = generateCellValuesContext.currentHeader; + // Just need to remove space string one time https://github.com/mini-software/MiniExcel/issues/751 var cleanOuterXmlOpen = CleanXml(outerXmlOpen, endPrefix); var cleanInnerXml = CleanXml(innerXml, endPrefix); @@ -748,7 +828,11 @@ private void GenerateCellValues(string endPrefix, StreamWriter writer, ref int r // replace formulas ProcessFormulas(rowXml, newRowIndex); - writer.Write(rowXml); + await writer.WriteAsync(rowXml.ToString() +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); //mergecells if (rowInfo.RowMercells == null) @@ -793,9 +877,24 @@ private void GenerateCellValues(string endPrefix, StreamWriter writer, ref int r } newRow.InnerXml = new StringBuilder(newRow.InnerXml).Replace("{{$rowindex}}", mergeBaseRowIndex.ToString()).ToString(); - writer.Write(CleanXml(newRow.OuterXml, endPrefix)); + await writer.WriteAsync(CleanXml(newRow.OuterXml, endPrefix) +#if NET7_0_OR_GREATER + .AsMemory(), ct +#endif + ).ConfigureAwait(false); } } + + return new GenerateCellValuesContext() + { + currentHeader = currentHeader, + headerDiff = headerDiff, + iEnumerableIndex = iEnumerableIndex, + isFirst = isFirst, + newRowIndex = newRowIndex, + prevHeader = prevHeader, + rowIndexDiff = rowIndexDiff, + }; } private static void MergeCells(List xRowInfos) diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs index 3fc5d179..4a2f17b8 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs @@ -14,21 +14,28 @@ namespace MiniExcelLibs.OpenXml.SaveByTemplate { internal partial class ExcelOpenXmlTemplate { - public void MergeSameCells(string path) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async Task MergeSameCellsAsync(string path, CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - MergeSameCellsImpl(stream); + await MergeSameCellsImplAsync(stream, ct).ConfigureAwait(false); } - public void MergeSameCells(byte[] fileInBytes) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken ct = default) { using (Stream stream = new MemoryStream(fileInBytes)) - MergeSameCellsImpl(stream); + await MergeSameCellsImplAsync(stream, ct).ConfigureAwait(false); } - private void MergeSameCellsImpl(Stream stream) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task MergeSameCellsImplAsync(Stream stream, CancellationToken ct = default) { - stream.CopyTo(_outputFileStream); + await stream.CopyToAsync(_outputFileStream +#if NETCOREAPP2_1_OR_GREATER + , ct +#endif + ).ConfigureAwait(false); var reader = new ExcelOpenXmlSheetReader(_outputFileStream, null); var archive = new ExcelOpenXmlZip(_outputFileStream, mode: ZipArchiveMode.Update, true, Encoding.UTF8); @@ -54,22 +61,12 @@ private void MergeSameCellsImpl(Stream stream) var entry = archive.zipFile.CreateEntry(fullName); using (var zipStream = entry.Open()) { - GenerateSheetXmlImplByUpdateMode(sheet, zipStream, sheetStream, new Dictionary(), sharedStrings, mergeCells: true); + await GenerateSheetXmlImplByUpdateModeAsync(sheet, zipStream, sheetStream, new Dictionary(), sharedStrings, mergeCells: true, ct).ConfigureAwait(false); //doc.Save(zipStream); //don't do it beacause: https://user-images.githubusercontent.com/12729184/114361127-61a5d100-9ba8-11eb-9bb9-34f076ee28a2.png } } archive.zipFile.Dispose(); } - - public Task MergeSameCellsAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) - { - return Task.Run(() => MergeSameCells(path), cancellationToken); - } - - public Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken cancellationToken = default(CancellationToken)) - { - return Task.Run(() => MergeSameCells(fileInBytes), cancellationToken); - } } } \ No newline at end of file diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs index b66838dd..e4fec69d 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs @@ -14,7 +14,7 @@ namespace MiniExcelLibs.OpenXml.SaveByTemplate { - internal partial class ExcelOpenXmlTemplate : IExcelTemplate, IExcelTemplateAsync + internal partial class ExcelOpenXmlTemplate : IExcelTemplateAsync { #if NET7_0_OR_GREATER [GeneratedRegex("(?<={{).*?(?=}})")] private static partial Regex ExpressionRegex(); @@ -43,19 +43,22 @@ public ExcelOpenXmlTemplate(Stream stream, IConfiguration configuration, InputVa _inputValueExtractor = inputValueExtractor; } - public void SaveAsByTemplate(string templatePath, object value) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(templatePath)) - SaveAsByTemplateImpl(stream, value); + await SaveAsByTemplateImplAsync(stream, value, ct).ConfigureAwait(false); } - public void SaveAsByTemplate(byte[] templateBtyes, object value) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async Task SaveAsByTemplateAsync(byte[] templateBytes, object value, CancellationToken ct = default) { - using (Stream stream = new MemoryStream(templateBtyes)) - SaveAsByTemplateImpl(stream, value); + using (Stream stream = new MemoryStream(templateBytes)) + await SaveAsByTemplateImplAsync(stream, value, ct).ConfigureAwait(false); } - internal void SaveAsByTemplateImpl(Stream templateStream, object value) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal async Task SaveAsByTemplateImplAsync(Stream templateStream, object value, CancellationToken ct = default) { //only support xlsx //templateStream.CopyTo(_outputFileStream); @@ -101,7 +104,11 @@ internal void SaveAsByTemplateImpl(Stream templateStream, object value) using (Stream originalEntryStream = entry.Open()) using (Stream newEntryStream = newEntry.Open()) { - originalEntryStream.CopyTo(newEntryStream); + await originalEntryStream.CopyToAsync(newEntryStream +#if NETCOREAPP2_1_OR_GREATER + , ct +#endif + ).ConfigureAwait(false); } } @@ -148,7 +155,7 @@ internal void SaveAsByTemplateImpl(Stream templateStream, object value) var calcChainEntry = outputFileArchive.zipFile.CreateEntry(calcChainPathName); using (var calcChainStream = calcChainEntry.Open()) { - CalcChainHelper.GenerateCalcChainSheet(calcChainStream, _calcChainContent.ToString()); + await CalcChainHelper.GenerateCalcChainSheetAsync(calcChainStream, _calcChainContent.ToString(), ct).ConfigureAwait(false); } } else @@ -163,7 +170,11 @@ internal void SaveAsByTemplateImpl(Stream templateStream, object value) using (Stream originalEntryStream = entry.Open()) using (Stream newEntryStream = newEntry.Open()) { - originalEntryStream.CopyTo(newEntryStream); + await originalEntryStream.CopyToAsync(newEntryStream +#if NETCOREAPP2_1_OR_GREATER + , ct +#endif + ).ConfigureAwait(false); } } } @@ -172,15 +183,5 @@ internal void SaveAsByTemplateImpl(Stream templateStream, object value) outputFileArchive.zipFile.Dispose(); } } - - public Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken cancellationToken = default) - { - return Task.Run(() => SaveAsByTemplate(templatePath, value), cancellationToken); - } - - public Task SaveAsByTemplateAsync(byte[] templateBtyes, object value, CancellationToken cancellationToken = default) - { - return Task.Run(() => SaveAsByTemplate(templateBtyes, value), cancellationToken); - } } } \ No newline at end of file diff --git a/src/MiniExcel/Utils/calChainHelper.cs b/src/MiniExcel/Utils/calChainHelper.cs index 1d40c30d..cd804c3f 100644 --- a/src/MiniExcel/Utils/calChainHelper.cs +++ b/src/MiniExcel/Utils/calChainHelper.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace MiniExcelLibs.Utils { - internal static class CalcChainHelper + internal static partial class CalcChainHelper { // The calcChain.xml file in an Excel file (in the xl folder) is an XML file that stores the calculation chain for the workbook. @@ -24,11 +26,12 @@ public static string GetCalcChainContent( List cellRefs, int sheetIndex return calcChainContent.ToString(); } - public static void GenerateCalcChainSheet(Stream calcChainStream, string calcChainContent) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task GenerateCalcChainSheetAsync(Stream calcChainStream, string calcChainContent, CancellationToken ct = default) { using (var writer = new StreamWriter(calcChainStream, Encoding.UTF8)) { - writer.Write($"{calcChainContent}"); + await writer.WriteAsync($"{calcChainContent}").ConfigureAwait(false); } } } diff --git a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs index cf7a3972..62293a0c 100644 --- a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs +++ b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs @@ -898,7 +898,7 @@ await Assert.ThrowsAsync(async () => }; await cts.CancelAsync(); - await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value, cancellationToken: cts.Token); + await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value, ct: cts.Token); }); } } \ No newline at end of file From 0873d0db2b383f1dd13dbe6f98a654594b774c15 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sat, 14 Jun 2025 06:35:14 -0400 Subject: [PATCH 09/25] Generate WriteCell from WriteCellAsync --- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 30 +++++++++---- .../OpenXml/ExcelOpenXmlSheetWriter.cs | 42 ------------------- 2 files changed, 23 insertions(+), 49 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 3e1e4561..a26b4ebc 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -362,18 +362,32 @@ private async Task PrintHeaderAsync(MiniExcelAsyncStreamWriter writer, List pro writer.Write(WorksheetXml.EndRow); } - private void WriteCell(MiniExcelStreamWriter writer, int rowIndex, int cellIndex, object value, ExcelColumnInfo columnInfo, ExcelWidthCollection widthCollection) - { - if (columnInfo?.CustomFormatter != null) - { - try - { - value = columnInfo.CustomFormatter(value); - } - catch - { - //ignored - } - } - - var columnReference = ExcelOpenXmlUtils.ConvertXyToCell(cellIndex, rowIndex); - var valueIsNull = value is null || - value is DBNull || - (_configuration.WriteEmptyStringAsNull && value is string vs && vs == string.Empty); - - if (_configuration.EnableWriteNullValueCell && valueIsNull) - { - writer.Write(WorksheetXml.EmptyCell(columnReference, GetCellXfId("2"))); - return; - } - - var tuple = GetCellValue(rowIndex, cellIndex, value, columnInfo, valueIsNull); - - var styleIndex = tuple.Item1; // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cell?view=openxml-3.0.1 - var dataType = tuple.Item2; // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cellvalues?view=openxml-3.0.1 - var cellValue = tuple.Item3; - - var columnType = columnInfo?.ExcelColumnType ?? ColumnType.Value; - - /*Prefix and suffix blank space will lost after SaveAs #294*/ - var preserveSpace = cellValue != null && (cellValue.StartsWith(" ", StringComparison.Ordinal) || cellValue.EndsWith(" ", StringComparison.Ordinal)); - writer.Write(WorksheetXml.Cell(columnReference, dataType, GetCellXfId(styleIndex), cellValue, preserveSpace: preserveSpace, columnType: columnType)); - widthCollection?.AdjustWidth(cellIndex, cellValue); - } - - private void WriteCell(MiniExcelStreamWriter writer, string cellReference, string columnName) - => writer.Write(WorksheetXml.Cell(cellReference, "str", GetCellXfId("1"), ExcelOpenXmlUtils.EncodeXML(columnName))); - private void GenerateEndXml() { AddFilesToZip(); From 00f07f05cd141a2e08615d6911f1947636ae87fd Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sat, 14 Jun 2025 09:41:39 -0400 Subject: [PATCH 10/25] Remove existing duplicate sync code --- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 4 + .../OpenXml/ExcelOpenXmlSheetWriter.cs | 68 --- .../Styles/DefaultSheetStyleBuilder.cs | 472 +----------------- .../OpenXml/Styles/ISheetStyleBuilder.cs | 5 +- .../Styles/MinimalSheetStyleBuilder.cs | 101 +--- .../OpenXml/Styles/SheetStyleBuilderBase.cs | 295 +---------- 6 files changed, 39 insertions(+), 906 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index a26b4ebc..07a9d3d3 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -421,6 +421,7 @@ value is DBNull || widthCollection?.AdjustWidth(cellIndex, cellValue); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateEndXmlAsync(CancellationToken cancellationToken) { await AddFilesToZipAsync(cancellationToken); @@ -430,6 +431,7 @@ private async Task GenerateEndXmlAsync(CancellationToken cancellationToken) await GenerateContentTypesXmlAsync(cancellationToken); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task AddFilesToZipAsync(CancellationToken cancellationToken) { foreach (var item in _files) @@ -439,6 +441,7 @@ private async Task AddFilesToZipAsync(CancellationToken cancellationToken) } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -535,6 +538,7 @@ private async Task GenerateContentTypesXmlAsync(CancellationToken cancellationTo await CreateZipEntryAsync(ExcelFileNames.ContentTypes, null, contentTypes, cancellationToken); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index be0267e4..35eea6a7 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -246,42 +246,6 @@ private void PrintHeader(MiniExcelStreamWriter writer, List pro writer.Write(WorksheetXml.EndRow); } - private void GenerateEndXml() - { - AddFilesToZip(); - GenerateDrawinRelXml(); - GenerateDrawingXml(); - GenerateWorkbookXml(); - GenerateContentTypesXml(); - } - - private void AddFilesToZip() - { - foreach (var item in _files) - { - CreateZipEntry(item.Path, item.Byte); - } - } - - private void GenerateStylesXml() - { - using (var context = new SheetStyleBuildContext(_zipDictionary, _archive, _utf8WithBom, _configuration.DynamicColumns)) - { - ISheetStyleBuilder builder = null; - switch (_configuration.TableStyles) - { - case TableStyles.None: - builder = new MinimalSheetStyleBuilder(context); - break; - case TableStyles.Default: - builder = new DefaultSheetStyleBuilder(context, _configuration.StyleOptions); - break; - } - var result = builder?.Build(); - _cellXfIdMap = result?.CellXfIdMap; - } - } - private void GenerateDrawinRelXml() { for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) @@ -349,38 +313,6 @@ private void GenerateContentTypesXml() CreateZipEntry(ExcelFileNames.ContentTypes, null, contentTypes); } - private void InsertContentTypesXml() - { - var contentTypesZipEntry = _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.ContentTypes); - if (contentTypesZipEntry == null) - { - GenerateContentTypesXml(); - return; - } - using (var stream = contentTypesZipEntry.Open()) - { - var doc = XDocument.Load(stream); - var ns = doc.Root?.GetDefaultNamespace(); - var typesElement = doc.Descendants(ns + "Types").Single(); - var partNames = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach (var partName in typesElement.Elements(ns + "Override").Select(s => s.Attribute("PartName")?.Value)) - { - partNames.Add(partName); - } - foreach (var p in _zipDictionary) - { - var partName = $"/{p.Key}"; - if (!partNames.Contains(partName)) - { - var newElement = new XElement(ns + "Override", new XAttribute("ContentType", p.Value.ContentType), new XAttribute("PartName", partName)); - typesElement.Add(newElement); - } - } - stream.Position = 0; - doc.Save(stream); - } - } - private void CreateZipEntry(string path, string contentType, string content) { ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest); diff --git a/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs b/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs index 793f1908..da0dfb7a 100644 --- a/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs +++ b/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs @@ -2,7 +2,7 @@ namespace MiniExcelLibs.OpenXml.Styles { - internal class DefaultSheetStyleBuilder : SheetStyleBuilderBase + internal partial class DefaultSheetStyleBuilder : SheetStyleBuilderBase { private static readonly SheetStyleElementInfos GenerateElementInfos = new SheetStyleElementInfos { @@ -28,25 +28,7 @@ protected override SheetStyleElementInfos GetGenerateElementInfos() return GenerateElementInfos; } - protected override void GenerateNumFmt() - { - const int numFmtIndex = 166; - - var index = 0; - foreach (var item in _context.ColumnsToApply) - { - index++; - - /* - * - * - * - * - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "font", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "vertAlign", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "baseline"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "sz", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "11"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "name", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "Calibri"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "family", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "2"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - * - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "font", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "vertAlign", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "baseline"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "sz", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "11"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FFFFFFFF"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "name", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "Calibri"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "family", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("val", "2"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateFontAsync() { /* @@ -179,47 +105,7 @@ protected override async Task GenerateFontAsync() await _context.NewXmlWriter.WriteEndElementAsync(); } - protected override void GenerateFill() - { - /* - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("patternType", "none"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("patternType", "gray125"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("patternType", "solid"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "fgColor", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "284472C4"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateFillAsync() { /* @@ -261,117 +147,7 @@ protected override async Task GenerateFillAsync() await _context.NewXmlWriter.WriteEndElementAsync(); } - protected override void GenerateBorder() - { - /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "border", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("diagonalUp", "0"); - _context.NewXmlWriter.WriteAttributeString("diagonalDown", "0"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "left", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "none"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "right", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "none"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "top", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "none"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "bottom", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "none"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "diagonal", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "none"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "border", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("diagonalUp", "0"); - _context.NewXmlWriter.WriteAttributeString("diagonalDown", "0"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "left", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "thin"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "right", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "thin"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "top", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "thin"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "bottom", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "thin"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "diagonal", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("style", "none"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("rgb", "FF000000"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateBorderAsync() { /* @@ -483,72 +259,7 @@ protected override async Task GenerateBorderAsync() await _context.NewXmlWriter.WriteEndElementAsync(); } - protected override void GenerateCellStyleXf() - { - /* - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "0"); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteAttributeString("applyFill", "1"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "0"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteAttributeString("applyProtection", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "protection", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("locked", "1"); - _context.NewXmlWriter.WriteAttributeString("hidden", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "14"); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 2}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteAttributeString("applyFill", "0"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "1"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteAttributeString("applyProtection", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "protection", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("locked", "1"); - _context.NewXmlWriter.WriteAttributeString("hidden", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "0"); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteAttributeString("applyFill", "1"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "1"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteAttributeString("applyProtection", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "protection", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("locked", "1"); - _context.NewXmlWriter.WriteAttributeString("hidden", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateCellStyleXfAsync() { /* @@ -615,176 +326,7 @@ protected override async Task GenerateCellStyleXfAsync() await _context.NewXmlWriter.WriteEndElementAsync(); } - protected override void GenerateCellXf() - { - /* - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "0"); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 2}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("xfId", "0"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteAttributeString("applyFill", "0"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "1"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteAttributeString("applyProtection", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "alignment", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("horizontal", "left"); - _context.NewXmlWriter.WriteAttributeString("vertical", "bottom"); - _context.NewXmlWriter.WriteAttributeString("textRotation", "0"); - _context.NewXmlWriter.WriteAttributeString("wrapText", "0"); - _context.NewXmlWriter.WriteAttributeString("indent", "0"); - _context.NewXmlWriter.WriteAttributeString("relativeIndent", "0"); - _context.NewXmlWriter.WriteAttributeString("justifyLastLine", "0"); - _context.NewXmlWriter.WriteAttributeString("shrinkToFit", "0"); - _context.NewXmlWriter.WriteAttributeString("readingOrder", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "protection", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("locked", "1"); - _context.NewXmlWriter.WriteAttributeString("hidden", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "0"); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("xfId", "0"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteAttributeString("applyFill", "1"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "1"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteAttributeString("applyProtection", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "alignment", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("horizontal", "general"); - _context.NewXmlWriter.WriteAttributeString("vertical", "bottom"); - _context.NewXmlWriter.WriteAttributeString("textRotation", "0"); - _context.NewXmlWriter.WriteAttributeString("wrapText", _styleOptions.WrapCellContents ? "1" : "0"); - _context.NewXmlWriter.WriteAttributeString("indent", "0"); - _context.NewXmlWriter.WriteAttributeString("relativeIndent", "0"); - _context.NewXmlWriter.WriteAttributeString("justifyLastLine", "0"); - _context.NewXmlWriter.WriteAttributeString("shrinkToFit", "0"); - _context.NewXmlWriter.WriteAttributeString("readingOrder", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "protection", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("locked", "1"); - _context.NewXmlWriter.WriteAttributeString("hidden", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "14"); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("xfId", "0"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteAttributeString("applyFill", "1"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "1"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteAttributeString("applyProtection", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "alignment", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("horizontal", "general"); - _context.NewXmlWriter.WriteAttributeString("vertical", "bottom"); - _context.NewXmlWriter.WriteAttributeString("textRotation", "0"); - _context.NewXmlWriter.WriteAttributeString("wrapText", "0"); - _context.NewXmlWriter.WriteAttributeString("indent", "0"); - _context.NewXmlWriter.WriteAttributeString("relativeIndent", "0"); - _context.NewXmlWriter.WriteAttributeString("justifyLastLine", "0"); - _context.NewXmlWriter.WriteAttributeString("shrinkToFit", "0"); - _context.NewXmlWriter.WriteAttributeString("readingOrder", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "protection", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("locked", "1"); - _context.NewXmlWriter.WriteAttributeString("hidden", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - /* - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "0"); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("xfId", "0"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "1"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "alignment", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("horizontal", "fill"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - - const int numFmtIndex = 166; - var index = 0; - foreach (var item in _context.ColumnsToApply) - { - index++; - - /* - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", (numFmtIndex + index + _context.OldElementInfos.NumFmtCount).ToString()); - _context.NewXmlWriter.WriteAttributeString("fontId", $"{_context.OldElementInfos.FontCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("fillId", $"{_context.OldElementInfos.FillCount + 0}"); - _context.NewXmlWriter.WriteAttributeString("borderId", $"{_context.OldElementInfos.BorderCount + 1}"); - _context.NewXmlWriter.WriteAttributeString("xfId", "0"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteAttributeString("applyFill", "1"); - _context.NewXmlWriter.WriteAttributeString("applyBorder", "1"); - _context.NewXmlWriter.WriteAttributeString("applyAlignment", "1"); - _context.NewXmlWriter.WriteAttributeString("applyProtection", "1"); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "alignment", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("horizontal", "general"); - _context.NewXmlWriter.WriteAttributeString("vertical", "bottom"); - _context.NewXmlWriter.WriteAttributeString("textRotation", "0"); - _context.NewXmlWriter.WriteAttributeString("wrapText", "0"); - _context.NewXmlWriter.WriteAttributeString("indent", "0"); - _context.NewXmlWriter.WriteAttributeString("relativeIndent", "0"); - _context.NewXmlWriter.WriteAttributeString("justifyLastLine", "0"); - _context.NewXmlWriter.WriteAttributeString("shrinkToFit", "0"); - _context.NewXmlWriter.WriteAttributeString("readingOrder", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "protection", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("locked", "1"); - _context.NewXmlWriter.WriteAttributeString("hidden", "0"); - _context.NewXmlWriter.WriteEndElement(); - _context.NewXmlWriter.WriteEndElement(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateCellXfAsync() { /* diff --git a/src/MiniExcel/OpenXml/Styles/ISheetStyleBuilder.cs b/src/MiniExcel/OpenXml/Styles/ISheetStyleBuilder.cs index 239fdde8..d268dc7d 100644 --- a/src/MiniExcel/OpenXml/Styles/ISheetStyleBuilder.cs +++ b/src/MiniExcel/OpenXml/Styles/ISheetStyleBuilder.cs @@ -3,10 +3,9 @@ namespace MiniExcelLibs.OpenXml.Styles { - internal interface ISheetStyleBuilder + internal partial interface ISheetStyleBuilder { - SheetStyleBuildResult Build(); - + [Zomp.SyncMethodGenerator.CreateSyncVersion] Task BuildAsync(CancellationToken cancellationToken = default); } } diff --git a/src/MiniExcel/OpenXml/Styles/MinimalSheetStyleBuilder.cs b/src/MiniExcel/OpenXml/Styles/MinimalSheetStyleBuilder.cs index e3af418e..45db2ae4 100644 --- a/src/MiniExcel/OpenXml/Styles/MinimalSheetStyleBuilder.cs +++ b/src/MiniExcel/OpenXml/Styles/MinimalSheetStyleBuilder.cs @@ -2,7 +2,7 @@ namespace MiniExcelLibs.OpenXml.Styles { - internal class MinimalSheetStyleBuilder : SheetStyleBuilderBase + internal partial class MinimalSheetStyleBuilder : SheetStyleBuilderBase { internal static SheetStyleElementInfos GenerateElementInfos = new SheetStyleElementInfos { @@ -26,25 +26,7 @@ protected override SheetStyleElementInfos GetGenerateElementInfos() return GenerateElementInfos; } - protected override void GenerateNumFmt() - { - const int numFmtIndex = 166; - - var index = 0; - foreach (var item in _context.ColumnsToApply) - { - index++; - - /* - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "numFmt", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", (numFmtIndex + index + _context.OldElementInfos.NumFmtCount).ToString()); - _context.NewXmlWriter.WriteAttributeString("formatCode", item.Format); - _context.NewXmlWriter.WriteFullEndElement(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateNumFmtAsync() { const int numFmtIndex = 166; @@ -63,15 +45,7 @@ protected override async Task GenerateNumFmtAsync() } } - protected override void GenerateFont() - { - /* - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "font", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateFontAsync() { /* @@ -81,15 +55,7 @@ protected override async Task GenerateFontAsync() await _context.NewXmlWriter.WriteFullEndElementAsync(); } - protected override void GenerateFill() - { - /* - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateFillAsync() { /* @@ -99,15 +65,7 @@ protected override async Task GenerateFillAsync() await _context.NewXmlWriter.WriteFullEndElementAsync(); } - protected override void GenerateBorder() - { - /* - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "border", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateBorderAsync() { /* @@ -117,15 +75,7 @@ protected override async Task GenerateBorderAsync() await _context.NewXmlWriter.WriteFullEndElementAsync(); } - protected override void GenerateCellStyleXf() - { - /* - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected override async Task GenerateCellStyleXfAsync() { /* @@ -135,44 +85,7 @@ protected override async Task GenerateCellStyleXfAsync() await _context.NewXmlWriter.WriteFullEndElementAsync(); } - protected override void GenerateCellXf() - { - /* - * - * - * - * - * - */ - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("numFmtId", "14"); - _context.NewXmlWriter.WriteAttributeString("applyNumberFormat", "1"); - _context.NewXmlWriter.WriteFullEndElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "xf", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteFullEndElement(); - - const int numFmtIndex = 166; - var index = 0; - foreach (var item in _context.ColumnsToApply) - { - index++; - - /* - * _allElements = new Dictionary { @@ -28,69 +28,11 @@ public SheetStyleBuilderBase(SheetStyleBuildContext context) _context = context; } - public virtual SheetStyleBuildResult Build() - { - _context.Initialize(GetGenerateElementInfos()); - - while (_context.OldXmlReader.Read()) - { - switch (_context.OldXmlReader.NodeType) - { - case XmlNodeType.Element: - GenerateElementBeforStartElement(); - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, _context.OldXmlReader.LocalName, _context.OldXmlReader.NamespaceURI); - WriteAttributes(_context.OldXmlReader.LocalName); - if (_context.OldXmlReader.IsEmptyElement) - { - GenerateElementBeforEndElement(); - _context.NewXmlWriter.WriteEndElement(); - } - break; - - case XmlNodeType.Text: - _context.NewXmlWriter.WriteString(_context.OldXmlReader.Value); - break; - - case XmlNodeType.Whitespace: - case XmlNodeType.SignificantWhitespace: - _context.NewXmlWriter.WriteWhitespace(_context.OldXmlReader.Value); - break; - - case XmlNodeType.CDATA: - _context.NewXmlWriter.WriteCData(_context.OldXmlReader.Value); - break; - - case XmlNodeType.EntityReference: - _context.NewXmlWriter.WriteEntityRef(_context.OldXmlReader.Name); - break; - - case XmlNodeType.XmlDeclaration: - case XmlNodeType.ProcessingInstruction: - _context.NewXmlWriter.WriteProcessingInstruction(_context.OldXmlReader.Name, _context.OldXmlReader.Value); - break; - case XmlNodeType.DocumentType: - _context.NewXmlWriter.WriteDocType(_context.OldXmlReader.Name, _context.OldXmlReader.GetAttribute("PUBLIC"), _context.OldXmlReader.GetAttribute("SYSTEM"), _context.OldXmlReader.Value); - break; - - case XmlNodeType.Comment: - _context.NewXmlWriter.WriteComment(_context.OldXmlReader.Value); - break; - case XmlNodeType.EndElement: - GenerateElementBeforEndElement(); - _context.NewXmlWriter.WriteFullEndElement(); - break; - } - } - - _context.FinalizeAndUpdateZipDictionary(); - - return new SheetStyleBuildResult(GetCellXfIdMap()); - } - - // Todo: add CancellationToken to all methods called inside of BuildAsync + // Todo: add CancellationToken to all methods called inside of BuildAsync + [Zomp.SyncMethodGenerator.CreateSyncVersion] public virtual async Task BuildAsync(CancellationToken cancellationToken = default) { - await _context.InitializeAsync(GetGenerateElementInfos(), cancellationToken); + await _context.InitializeAsync(GetGenerateElementInfos(), cancellationToken).ConfigureAwait(false); while (await _context.OldXmlReader.ReadAsync()) { @@ -145,66 +87,7 @@ public virtual async Task BuildAsync(CancellationToken ca protected abstract SheetStyleElementInfos GetGenerateElementInfos(); - protected virtual void WriteAttributes(string element) - { - if (_context.OldXmlReader.NodeType is XmlNodeType.Element || _context.OldXmlReader.NodeType is XmlNodeType.XmlDeclaration) - { - if (_context.OldXmlReader.MoveToFirstAttribute()) - { - WriteAttributes(element); - _context.OldXmlReader.MoveToElement(); - } - } - else if (_context.OldXmlReader.NodeType == XmlNodeType.Attribute) - { - do - { - _context.NewXmlWriter.WriteStartAttribute(_context.OldXmlReader.Prefix, _context.OldXmlReader.LocalName, _context.OldXmlReader.NamespaceURI); - var currentAttribute = _context.OldXmlReader.LocalName; - while (_context.OldXmlReader.ReadAttributeValue()) - { - if (_context.OldXmlReader.NodeType == XmlNodeType.EntityReference) - { - _context.NewXmlWriter.WriteEntityRef(_context.OldXmlReader.Name); - } - else if (currentAttribute == "count") - { - switch (element) - { - case "numFmts": - _context.NewXmlWriter.WriteString((_context.OldElementInfos.NumFmtCount + _context.GenerateElementInfos.NumFmtCount + _context.CustomFormatCount).ToString()); - break; - case "fonts": - _context.NewXmlWriter.WriteString((_context.OldElementInfos.FontCount + _context.GenerateElementInfos.FontCount).ToString()); - break; - case "fills": - _context.NewXmlWriter.WriteString((_context.OldElementInfos.FillCount + _context.GenerateElementInfos.FillCount).ToString()); - break; - case "borders": - _context.NewXmlWriter.WriteString((_context.OldElementInfos.BorderCount + _context.GenerateElementInfos.BorderCount).ToString()); - break; - case "cellStyleXfs": - _context.NewXmlWriter.WriteString((_context.OldElementInfos.CellStyleXfCount + _context.GenerateElementInfos.CellStyleXfCount).ToString()); - break; - case "cellXfs": - _context.NewXmlWriter.WriteString((_context.OldElementInfos.CellXfCount + _context.GenerateElementInfos.CellXfCount + _context.CustomFormatCount).ToString()); - break; - default: - _context.NewXmlWriter.WriteString(_context.OldXmlReader.Value); - break; - } - } - else - { - _context.NewXmlWriter.WriteString(_context.OldXmlReader.Value); - } - } - _context.NewXmlWriter.WriteEndAttribute(); - } - while (_context.OldXmlReader.MoveToNextAttribute()); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task WriteAttributesAsync(string element, CancellationToken cancellationToken = default) { if (_context.OldXmlReader.NodeType is XmlNodeType.Element || _context.OldXmlReader.NodeType is XmlNodeType.XmlDeclaration) @@ -267,44 +150,7 @@ protected virtual async Task WriteAttributesAsync(string element, CancellationTo } } - protected virtual void GenerateElementBeforStartElement() - { - if (!_allElements.TryGetValue(_context.OldXmlReader.LocalName, out var elementIndex)) - { - return; - } - if (!_context.OldElementInfos.ExistsNumFmts && !_context.GenerateElementInfos.ExistsNumFmts && _allElements["numFmts"] < elementIndex) - { - GenerateNumFmts(); - _context.GenerateElementInfos.ExistsNumFmts = true; - } - else if (!_context.OldElementInfos.ExistsFonts && !_context.GenerateElementInfos.ExistsFonts && _allElements["fonts"] < elementIndex) - { - GenerateFonts(); - _context.GenerateElementInfos.ExistsFonts = true; - } - else if (!_context.OldElementInfos.ExistsFills && !_context.GenerateElementInfos.ExistsFills && _allElements["fills"] < elementIndex) - { - GenerateFills(); - _context.GenerateElementInfos.ExistsFills = true; - } - else if (!_context.OldElementInfos.ExistsBorders && !_context.GenerateElementInfos.ExistsBorders && _allElements["borders"] < elementIndex) - { - GenerateBorders(); - _context.GenerateElementInfos.ExistsBorders = true; - } - else if (!_context.OldElementInfos.ExistsCellStyleXfs && !_context.GenerateElementInfos.ExistsCellStyleXfs && _allElements["cellStyleXfs"] < elementIndex) - { - GenerateCellStyleXfs(); - _context.GenerateElementInfos.ExistsCellStyleXfs = true; - } - else if (!_context.OldElementInfos.ExistsCellXfs && !_context.GenerateElementInfos.ExistsCellXfs && _allElements["cellXfs"] < elementIndex) - { - GenerateCellXfs(); - _context.GenerateElementInfos.ExistsCellXfs = true; - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateElementBeforStartElementAsync() { if (!_allElements.TryGetValue(_context.OldXmlReader.LocalName, out var elementIndex)) @@ -343,38 +189,7 @@ protected virtual async Task GenerateElementBeforStartElementAsync() } } - protected virtual void GenerateElementBeforEndElement() - { - if (_context.OldXmlReader.LocalName == "styleSheet" && !_context.OldElementInfos.ExistsNumFmts && !_context.GenerateElementInfos.ExistsNumFmts) - { - GenerateNumFmts(); - } - else if (_context.OldXmlReader.LocalName == "numFmts") - { - GenerateNumFmt(); - } - else if (_context.OldXmlReader.LocalName == "fonts") - { - GenerateFont(); - } - else if (_context.OldXmlReader.LocalName == "fills") - { - GenerateFill(); - } - else if (_context.OldXmlReader.LocalName == "borders") - { - GenerateBorder(); - } - else if (_context.OldXmlReader.LocalName == "cellStyleXfs") - { - GenerateCellStyleXf(); - } - else if (_context.OldXmlReader.LocalName == "cellXfs") - { - GenerateCellXf(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateElementBeforEndElementAsync() { switch (_context.OldXmlReader.LocalName) @@ -403,19 +218,7 @@ protected virtual async Task GenerateElementBeforEndElementAsync() } } - protected virtual void GenerateNumFmts() - { - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "numFmts", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("count", (_context.OldElementInfos.NumFmtCount + _context.GenerateElementInfos.NumFmtCount + _context.CustomFormatCount).ToString()); - GenerateNumFmt(); - _context.NewXmlWriter.WriteFullEndElement(); - - if (!_context.OldElementInfos.ExistsFonts) - { - GenerateFonts(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateNumFmtsAsync() { await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "numFmts", _context.OldXmlReader.NamespaceURI); @@ -429,23 +232,10 @@ protected virtual async Task GenerateNumFmtsAsync() } } - protected abstract void GenerateNumFmt(); - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected abstract Task GenerateNumFmtAsync(); - protected virtual void GenerateFonts() - { - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "fonts", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("count", (_context.OldElementInfos.FontCount + _context.GenerateElementInfos.FontCount).ToString()); - GenerateFont(); - _context.NewXmlWriter.WriteFullEndElement(); - - if (!_context.OldElementInfos.ExistsFills) - { - GenerateFills(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateFontsAsync() { await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fonts", _context.OldXmlReader.NamespaceURI); @@ -459,22 +249,10 @@ protected virtual async Task GenerateFontsAsync() } } - protected abstract void GenerateFont(); - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected abstract Task GenerateFontAsync(); - protected virtual void GenerateFills() - { - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "fills", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("count", (_context.OldElementInfos.FillCount + _context.GenerateElementInfos.FillCount).ToString()); - GenerateFill(); - _context.NewXmlWriter.WriteFullEndElement(); - if (!_context.OldElementInfos.ExistsBorders) - { - GenerateBorders(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateFillsAsync() { await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fills", _context.OldXmlReader.NamespaceURI); @@ -488,23 +266,10 @@ protected virtual async Task GenerateFillsAsync() } } - protected abstract void GenerateFill(); - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected abstract Task GenerateFillAsync(); - protected virtual void GenerateBorders() - { - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "borders", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("count", (_context.OldElementInfos.BorderCount + _context.GenerateElementInfos.BorderCount).ToString()); - GenerateBorder(); - _context.NewXmlWriter.WriteFullEndElement(); - - if (!_context.OldElementInfos.ExistsCellStyleXfs) - { - GenerateCellStyleXfs(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateBordersAsync() { await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "borders", _context.OldXmlReader.NamespaceURI); @@ -518,23 +283,10 @@ protected virtual async Task GenerateBordersAsync() } } - protected abstract void GenerateBorder(); - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected abstract Task GenerateBorderAsync(); - protected virtual void GenerateCellStyleXfs() - { - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "cellStyleXfs", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("count", (_context.OldElementInfos.CellStyleXfCount + _context.GenerateElementInfos.CellStyleXfCount).ToString()); - GenerateCellStyleXf(); - _context.NewXmlWriter.WriteFullEndElement(); - - if (!_context.OldElementInfos.ExistsCellXfs) - { - GenerateCellXfs(); - } - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateCellStyleXfsAsync() { await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "cellStyleXfs", _context.OldXmlReader.NamespaceURI); @@ -548,18 +300,10 @@ protected virtual async Task GenerateCellStyleXfsAsync() } } - protected abstract void GenerateCellStyleXf(); - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected abstract Task GenerateCellStyleXfAsync(); - protected virtual void GenerateCellXfs() - { - _context.NewXmlWriter.WriteStartElement(_context.OldXmlReader.Prefix, "cellXfs", _context.OldXmlReader.NamespaceURI); - _context.NewXmlWriter.WriteAttributeString("count", (_context.OldElementInfos.CellXfCount + _context.GenerateElementInfos.CellXfCount + _context.CustomFormatCount).ToString()); - GenerateCellXf(); - _context.NewXmlWriter.WriteFullEndElement(); - } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected virtual async Task GenerateCellXfsAsync() { await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "cellXfs", _context.OldXmlReader.NamespaceURI); @@ -568,8 +312,7 @@ protected virtual async Task GenerateCellXfsAsync() await _context.NewXmlWriter.WriteFullEndElementAsync(); } - protected abstract void GenerateCellXf(); - + [Zomp.SyncMethodGenerator.CreateSyncVersion] protected abstract Task GenerateCellXfAsync(); private Dictionary GetCellXfIdMap() From 61c323949c7f4a7b7f40f9e6b828b4c05a411b89 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sat, 14 Jun 2025 10:26:29 -0400 Subject: [PATCH 11/25] Factor out ExcelOpenXmlSheetWriter where sync and async do not diverge --- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 67 +++++++++- .../OpenXml/ExcelOpenXmlSheetWriter.cs | 123 ------------------ 2 files changed, 60 insertions(+), 130 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 07a9d3d3..67c06629 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -116,6 +116,7 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async Task GenerateDefaultOpenXmlAsync(CancellationToken cancellationToken) { await CreateZipEntryAsync(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels, cancellationToken); @@ -151,7 +152,14 @@ private static async Task WriteEmptySheetAsync(MiniExcelAsyncStreamWriter writer await writer.WriteAsync(ExcelXml.EmptySheetXml); } - private static async Task WriteDimensionPlaceholderAsync(MiniExcelAsyncStreamWriter writer) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private static async Task WriteDimensionPlaceholderAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer +#else + MiniExcelAsyncStreamWriter writer +#endif + ) { var dimensionPlaceholderPostition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension); await writer.WriteAsync(WorksheetXml.DimensionPlaceholder); // end of code will be replaced @@ -159,7 +167,14 @@ private static async Task WriteDimensionPlaceholderAsync(MiniExcelAsyncStr return dimensionPlaceholderPostition; } - private static async Task WriteDimensionAsync(MiniExcelAsyncStreamWriter writer, int maxRowIndex, int maxColumnIndex, long placeholderPosition) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private static async Task WriteDimensionAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + int maxRowIndex, int maxColumnIndex, long placeholderPosition) { // Flush and save position so that we can get back again. var position = await writer.FlushAsync(); @@ -170,6 +185,8 @@ private static async Task WriteDimensionAsync(MiniExcelAsyncStreamWriter writer, writer.SetPosition(position); } + // Async and sync diverge. Do not apply the attribute + //[Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, object values, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -290,21 +307,36 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje } if (_configuration.EnableAutoWidth) { - await OverWriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns, cancellationToken); + await OverwriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns, cancellationToken); } var toSubtract = _printHeader ? 1 : 0; return maxRowIndex - toSubtract; } - private static async Task WriteColumnWidthPlaceholdersAsync(MiniExcelAsyncStreamWriter writer, ICollection props) + // Async and sync diverge. Do not apply the attribute + //[Zomp.SyncMethodGenerator.CreateSyncVersion] + private static async Task WriteColumnWidthPlaceholdersAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + ICollection props) { var placeholderPosition = await writer.FlushAsync(); await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(props.Count)); return placeholderPosition; } - private static async Task OverWriteColumnWidthPlaceholdersAsync(MiniExcelAsyncStreamWriter writer, long placeholderPosition, IEnumerable columnWidths, CancellationToken cancellationToken = default) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private static async Task OverwriteColumnWidthPlaceholdersAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + long placeholderPosition, IEnumerable columnWidths, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -317,7 +349,14 @@ private static async Task OverWriteColumnWidthPlaceholdersAsync(MiniExcelAsyncSt writer.SetPosition(position); } - private static async Task WriteColumnsWidthsAsync(MiniExcelAsyncStreamWriter writer, IEnumerable columnWidths, CancellationToken cancellationToken = default) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private static async Task WriteColumnsWidthsAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + IEnumerable columnWidths, CancellationToken cancellationToken = default) { var hasWrittenStart = false; foreach (var column in columnWidths) @@ -338,7 +377,15 @@ private static async Task WriteColumnsWidthsAsync(MiniExcelAsyncStreamWriter wri await writer.WriteAsync(WorksheetXml.EndCols); } - private async Task PrintHeaderAsync(MiniExcelAsyncStreamWriter writer, List props, CancellationToken cancellationToken = default) + // Async and sync diverge. Do not apply the attribute + //[Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task PrintHeaderAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + List props, CancellationToken cancellationToken = default) { var xIndex = 1; var yIndex = 1; @@ -463,6 +510,7 @@ private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken) } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateDrawinRelXmlAsync(CancellationToken cancellationToken) { for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) @@ -472,6 +520,7 @@ private async Task GenerateDrawinRelXmlAsync(CancellationToken cancellationToken } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateDrawinRelXmlAsync(int sheetIndex, CancellationToken cancellationToken) { var drawing = GetDrawingRelationshipXml(sheetIndex); @@ -482,6 +531,7 @@ await CreateZipEntryAsync( cancellationToken); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateDrawingXmlAsync(CancellationToken cancellationToken) { for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) @@ -491,6 +541,7 @@ private async Task GenerateDrawingXmlAsync(CancellationToken cancellationToken) } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateDrawingXmlAsync(int sheetIndex, CancellationToken cancellationToken) { var drawing = GetDrawingXml(sheetIndex); @@ -501,6 +552,7 @@ await CreateZipEntryAsync( cancellationToken); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateWorkbookXmlAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -532,6 +584,7 @@ await CreateZipEntryAsync( cancellationToken); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateContentTypesXmlAsync(CancellationToken cancellationToken) { var contentTypes = GetContentTypesXml(); diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index 35eea6a7..1fcc64a7 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -45,13 +45,6 @@ public ExcelOpenXmlSheetWriter(Stream stream, object value, string sheetName, IC _defaultSheetName = sheetName; } - internal void GenerateDefaultOpenXml() - { - CreateZipEntry(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels); - CreateZipEntry(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString); - GenerateStylesXml(); - } - private int CreateSheetXml(object values, string sheetPath) { var entry = _archive.CreateEntry(sheetPath, CompressionLevel.Fastest); @@ -78,25 +71,6 @@ private static void WriteEmptySheet(MiniExcelStreamWriter writer) writer.Write(ExcelXml.EmptySheetXml); } - private static long WriteDimensionPlaceholder(MiniExcelStreamWriter writer) - { - var dimensionPlaceholderPostition = writer.WriteAndFlush(WorksheetXml.StartDimension); - writer.Write(WorksheetXml.DimensionPlaceholder); // end of code will be replaced - - return dimensionPlaceholderPostition; - } - - private static void WriteDimension(MiniExcelStreamWriter writer, int maxRowIndex, int maxColumnIndex, long placeholderPosition) - { - // Flush and save position so that we can get back again. - var position = writer.Flush(); - - writer.SetPosition(placeholderPosition); - writer.WriteAndFlush($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}"""); - - writer.SetPosition(position); - } - private int WriteValues(MiniExcelStreamWriter writer, object values) { var writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration); @@ -193,36 +167,6 @@ private static long WriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, i return placeholderPosition; } - private static void OverwriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, long placeholderPosition, IEnumerable columnWidths) - { - var position = writer.Flush(); - - writer.SetPosition(placeholderPosition); - WriteColumnsWidths(writer, columnWidths); - - writer.Flush(); - writer.SetPosition(position); - } - - private static void WriteColumnsWidths(MiniExcelStreamWriter writer, IEnumerable columnWidths) - { - var hasWrittenStart = false; - foreach (var column in columnWidths) - { - if (!hasWrittenStart) - { - writer.Write(WorksheetXml.StartCols); - hasWrittenStart = true; - } - writer.Write(WorksheetXml.Column(column.Index, column.Width)); - } - - if (hasWrittenStart) - { - writer.Write(WorksheetXml.EndCols); - } - } - private void PrintHeader(MiniExcelStreamWriter writer, List props) { const int yIndex = 1; @@ -246,73 +190,6 @@ private void PrintHeader(MiniExcelStreamWriter writer, List pro writer.Write(WorksheetXml.EndRow); } - private void GenerateDrawinRelXml() - { - for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) - { - GenerateDrawinRelXml(sheetIndex); - } - } - - private void GenerateDrawinRelXml(int sheetIndex) - { - var drawing = GetDrawingRelationshipXml(sheetIndex); - CreateZipEntry( - ExcelFileNames.DrawingRels(sheetIndex), - null, - ExcelXml.DefaultDrawingXmlRels.Replace("{{format}}", drawing)); - } - - private void GenerateDrawingXml() - { - for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) - { - GenerateDrawingXml(sheetIndex); - } - } - - private void GenerateDrawingXml(int sheetIndex) - { - var drawing = GetDrawingXml(sheetIndex); - CreateZipEntry( - ExcelFileNames.Drawing(sheetIndex), - ExcelContentTypes.Drawing, - ExcelXml.DefaultDrawing.Replace("{{format}}", drawing)); - } - - private void GenerateWorkbookXml() - { - GenerateWorkBookXmls( - out StringBuilder workbookXml, - out StringBuilder workbookRelsXml, - out Dictionary sheetsRelsXml); - - foreach (var sheetRelsXml in sheetsRelsXml) - { - CreateZipEntry( - ExcelFileNames.SheetRels(sheetRelsXml.Key), - null, - ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value)); - } - - CreateZipEntry( - ExcelFileNames.Workbook, - ExcelContentTypes.Workbook, - ExcelXml.DefaultWorkbookXml.Replace("{{sheets}}", workbookXml.ToString())); - - CreateZipEntry( - ExcelFileNames.WorkbookRels, - null, - ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString())); - } - - private void GenerateContentTypesXml() - { - var contentTypes = GetContentTypesXml(); - - CreateZipEntry(ExcelFileNames.ContentTypes, null, contentTypes); - } - private void CreateZipEntry(string path, string contentType, string content) { ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest); From 39b2b1ebe5afc1f3ee6e8ee35f4f17aa51f18e04 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 00:10:52 -0400 Subject: [PATCH 12/25] Use ExcelOpenXmlSheetReader.CreateAsync --- src/MiniExcel/ExcelFactory.cs | 2 +- src/MiniExcel/MiniExcel.cs | 79 ++++++++++++------- .../OpenXml/ExcelOpenXmlSheetReader.cs | 34 ++++---- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 5 +- .../Picture/MiniExcelPictureImplement.cs | 10 ++- .../ExcelOpenXmlTemplate.MergeCells.cs | 2 +- .../SaveByTemplate/ExcelOpenXmlTemplate.cs | 2 +- src/MiniExcel/Utils/XmlReaderHelper.cs | 20 ++++- 8 files changed, 98 insertions(+), 56 deletions(-) diff --git a/src/MiniExcel/ExcelFactory.cs b/src/MiniExcel/ExcelFactory.cs index 36760508..8f6dba31 100644 --- a/src/MiniExcel/ExcelFactory.cs +++ b/src/MiniExcel/ExcelFactory.cs @@ -15,7 +15,7 @@ internal static IExcelReader GetProvider(Stream stream, ExcelType excelType, ICo case ExcelType.CSV: return new CsvReader(stream, configuration); case ExcelType.XLSX: - return new ExcelOpenXmlSheetReader(stream, configuration); + return ExcelOpenXmlSheetReader.Create(stream, configuration); default: throw new NotSupportedException("Something went wrong. Please report this issue you are experiencing with MiniExcel."); } diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index c9d69d0f..6cad3bc4 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -109,7 +109,7 @@ public static async Task SaveAsAsync(this Stream stream, object value, bo await foreach (var item in excelReader.QueryAsync(sheetName, startCell, hasHeader, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async IAsyncEnumerable QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { @@ -117,7 +117,7 @@ public static async IAsyncEnumerable QueryAsync(string path, bool useHe await foreach (var item in QueryAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; } - + [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async IAsyncEnumerable QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { @@ -165,7 +165,7 @@ public static IEnumerable QueryRange(string path, bool useHeaderRow = f foreach (var item in QueryRange(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration)) yield return item; } - + public static IEnumerable QueryRange(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null) { using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) @@ -282,82 +282,105 @@ public static DataTable QueryAsDataTable(this Stream stream, bool useHeaderRow = return dt; } - public static List GetSheetNames(string path, OpenXmlConfiguration config = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetNamesAsync(string path, OpenXmlConfiguration config = null, CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetSheetNames(stream, config); + return await GetSheetNamesAsync(stream, config, ct); } - public static List GetSheetNames(this Stream stream, OpenXmlConfiguration config = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetNamesAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken ct = default) { config = config ?? OpenXmlConfiguration.DefaultConfig; var archive = new ExcelOpenXmlZip(stream); - return new ExcelOpenXmlSheetReader(stream, config).GetWorkbookRels(archive.entries).Select(s => s.Name).ToList(); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, ct: ct).ConfigureAwait(false); + var rels = await reader.GetWorkbookRelsAsync(archive.entries, ct).ConfigureAwait(false); + return rels.Select(s => s.Name).ToList(); } - public static List GetSheetInformations(string path, OpenXmlConfiguration config = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetInformationsAsync(string path, OpenXmlConfiguration config = null, CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetSheetInformations(stream, config); + return await GetSheetInformationsAsync(stream, config, ct).ConfigureAwait(false); } - public static List GetSheetInformations(this Stream stream, OpenXmlConfiguration config = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetInformationsAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken ct = default) { config = config ?? OpenXmlConfiguration.DefaultConfig; var archive = new ExcelOpenXmlZip(stream); - return new ExcelOpenXmlSheetReader(stream, config).GetWorkbookRels(archive.entries).Select((s, i) => s.ToSheetInfo((uint)i)).ToList(); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, ct: ct).ConfigureAwait(false); + var rels = await reader.GetWorkbookRelsAsync(archive.entries, ct).ConfigureAwait(false); + return rels.Select((s, i) => s.ToSheetInfo((uint)i)).ToList(); } - public static ICollection GetColumns(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetColumnsAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetColumns(stream, useHeaderRow, sheetName, excelType, startCell, configuration); + return await GetColumnsAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration, ct).ConfigureAwait(false); } - public static ICollection GetColumns(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetColumnsAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) { - return (Query(stream, useHeaderRow, sheetName, excelType, startCell, configuration).FirstOrDefault() as IDictionary)?.Keys; + var enumerator = QueryAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration).GetAsyncEnumerator(ct); + _ = enumerator.ConfigureAwait(false); + if (!await enumerator.MoveNextAsync()) + { + return null; + } + return (enumerator.Current as IDictionary)?.Keys; } - public static IList GetSheetDimensions(string path) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetDimensionsAsync(string path, CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetSheetDimensions(stream); + return await GetSheetDimensionsAsync(stream, ct).ConfigureAwait(false); } - public static IList GetSheetDimensions(this Stream stream) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetDimensionsAsync(this Stream stream, CancellationToken ct = default) { - return new ExcelOpenXmlSheetReader(stream, null).GetDimensions(); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, null, ct: ct).ConfigureAwait(false); + return reader.GetDimensions(); } - public static void ConvertCsvToXlsx(string csv, string xlsx) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ConvertCsvToXlsxAsync(string csv, string xlsx, CancellationToken ct = default) { using (var csvStream = FileHelper.OpenSharedRead(csv)) using (var xlsxStream = new FileStream(xlsx, FileMode.CreateNew)) { - ConvertCsvToXlsx(csvStream, xlsxStream); + await ConvertCsvToXlsxAsync(csvStream, xlsxStream, ct: ct).ConfigureAwait(false); } } - public static void ConvertCsvToXlsx(Stream csv, Stream xlsx) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ConvertCsvToXlsxAsync(Stream csv, Stream xlsx, CancellationToken ct = default) { - var value = Query(csv, useHeaderRow: false, excelType: ExcelType.CSV); - SaveAs(xlsx, value, printHeader: false, excelType: ExcelType.XLSX); + var value = QueryAsync(csv, useHeaderRow: false, excelType: ExcelType.CSV); + await SaveAsAsync(xlsx, value, printHeader: false, excelType: ExcelType.XLSX, ct: ct).ConfigureAwait(false); } - public static void ConvertXlsxToCsv(string xlsx, string csv) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ConvertXlsxToCsvAsync(string xlsx, string csv, CancellationToken ct = default) { using (var xlsxStream = FileHelper.OpenSharedRead(xlsx)) using (var csvStream = new FileStream(csv, FileMode.CreateNew)) - ConvertXlsxToCsv(xlsxStream, csvStream); + await ConvertXlsxToCsvAsync(xlsxStream, csvStream, ct).ConfigureAwait(false); } - public static void ConvertXlsxToCsv(Stream xlsx, Stream csv) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ConvertXlsxToCsvAsync(Stream xlsx, Stream csv, CancellationToken ct = default) { var value = Query(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX); - SaveAs(csv, value, printHeader: false, excelType: ExcelType.CSV); + await SaveAsAsync(csv, value, printHeader: false, excelType: ExcelType.CSV, ct: ct).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs index 7344872d..b37b3b6e 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs @@ -27,11 +27,18 @@ internal partial class ExcelOpenXmlSheetReader : IExcelReader internal readonly ExcelOpenXmlZip _archive; private readonly OpenXmlConfiguration _config; - public ExcelOpenXmlSheetReader(Stream stream, IConfiguration configuration, bool isUpdateMode = true) + private ExcelOpenXmlSheetReader(Stream stream, IConfiguration configuration, bool isUpdateMode) { _archive = new ExcelOpenXmlZip(stream); _config = (OpenXmlConfiguration)configuration ?? OpenXmlConfiguration.DefaultConfig; - SetSharedStrings(); + } + + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task CreateAsync(Stream stream, IConfiguration configuration, bool isUpdateMode = true, CancellationToken ct = default) + { + var reader = new ExcelOpenXmlSheetReader(stream, configuration, isUpdateMode); + await reader.SetSharedStringsAsync(ct).ConfigureAwait(false); + return reader; } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -133,7 +140,7 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async IAsyncEnumerable> InternalQueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, [EnumeratorCancellation] CancellationToken ct = default) { - var xmlSettings = GetXmlReaderSettings( + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false #else @@ -439,17 +446,6 @@ private static void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, } } - private static XmlReaderSettings GetXmlReaderSettings(bool async) - { - return new XmlReaderSettings - { - IgnoreComments = true, - IgnoreWhitespace = true, - XmlResolver = null, - Async = async, - }; - } - [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task SetSharedStringsAsync(CancellationToken ct = default) { @@ -489,7 +485,7 @@ private void SetWorkbookRels(ReadOnlyCollection entries) [Zomp.SyncMethodGenerator.CreateSyncVersion] internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCollection entries, [EnumeratorCancellation] CancellationToken ct = default) { - var xmlSettings = GetXmlReaderSettings( + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false #else @@ -570,7 +566,7 @@ internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCo [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async Task> GetWorkbookRelsAsync(ReadOnlyCollection entries, CancellationToken ct = default) { - var xmlSettings = GetXmlReaderSettings( + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false #else @@ -775,7 +771,7 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async Task> GetDimensionsAsync(CancellationToken ct = default) { - var xmlSettings = GetXmlReaderSettings( + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false #else @@ -935,7 +931,7 @@ public GetMaxRowColumnIndexResult(bool isSuccess, bool withoutCR, int maxRowInde [Zomp.SyncMethodGenerator.CreateSyncVersion] internal static async Task TryGetMaxRowColumnIndexAsync(ZipArchiveEntry sheetEntry, CancellationToken ct = default) { - var xmlSettings = GetXmlReaderSettings( + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false #else @@ -1072,7 +1068,7 @@ public MergeCellsResult(bool isSuccess, MergeCells mergeCells) [Zomp.SyncMethodGenerator.CreateSyncVersion] internal static async Task TryGetMergeCellsAsync(ZipArchiveEntry sheetEntry, CancellationToken ct = default) { - var xmlSettings = GetXmlReaderSettings( + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false #else diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 67c06629..3f88c082 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -55,8 +55,9 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke throw new InvalidOperationException("Insert requires fast mode to be enabled"); cancellationToken.ThrowIfCancellationRequested(); - - var sheetRecords = (await new ExcelOpenXmlSheetReader(_stream, _configuration).GetWorkbookRelsAsync(_archive.Entries, cancellationToken).ConfigureAwait(false)).ToArray(); + + var reader = await ExcelOpenXmlSheetReader.CreateAsync(_stream, _configuration, ct: cancellationToken).ConfigureAwait(false); + var sheetRecords = (await reader.GetWorkbookRelsAsync(_archive.Entries, cancellationToken).ConfigureAwait(false)).ToArray(); foreach (var sheetRecord in sheetRecords.OrderBy(o => o.Id)) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/MiniExcel/Picture/MiniExcelPictureImplement.cs b/src/MiniExcel/Picture/MiniExcelPictureImplement.cs index cef2677e..73ecb3d7 100644 --- a/src/MiniExcel/Picture/MiniExcelPictureImplement.cs +++ b/src/MiniExcel/Picture/MiniExcelPictureImplement.cs @@ -4,17 +4,21 @@ using System.IO; using System.IO.Compression; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using System.Xml; namespace MiniExcelLibs.Picture { - internal static class MiniExcelPictureImplement + internal static partial class MiniExcelPictureImplement { - public static void AddPicture(Stream excelStream, params MiniExcelPicture[] images) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task AddPictureAsync(Stream excelStream, CancellationToken ct = default, params MiniExcelPicture[] images) { // get sheets var excelArchive = new ExcelOpenXmlZip(excelStream); - var sheetEntries = new ExcelOpenXmlSheetReader(excelStream, null).GetWorkbookRels(excelArchive.entries).ToList(); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(excelStream, null, ct: ct).ConfigureAwait(false); + var sheetEntries = await reader.GetWorkbookRelsAsync(excelArchive.entries, ct).ConfigureAwait(false); var drawingRelId = $"rId{Guid.NewGuid():N}"; var drawingId = Guid.NewGuid().ToString("N"); diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs index 4a2f17b8..63763c2c 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs @@ -37,7 +37,7 @@ await stream.CopyToAsync(_outputFileStream #endif ).ConfigureAwait(false); - var reader = new ExcelOpenXmlSheetReader(_outputFileStream, null); + var reader = await ExcelOpenXmlSheetReader.CreateAsync (_outputFileStream, null, ct: ct).ConfigureAwait(false); var archive = new ExcelOpenXmlZip(_outputFileStream, mode: ZipArchiveMode.Update, true, Encoding.UTF8); //read sharedString diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs index e4fec69d..4c7c66f2 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs @@ -65,7 +65,7 @@ internal async Task SaveAsByTemplateImplAsync(Stream templateStream, object valu // foreach all templateStream and create file for _outputFileStream and not create sheet file templateStream.Position = 0; - var templateReader = new ExcelOpenXmlSheetReader(templateStream, null); + var templateReader = await ExcelOpenXmlSheetReader.CreateAsync(templateStream, null, ct: ct).ConfigureAwait(false); var outputFileArchive = new ExcelOpenXmlZip(_outputFileStream, mode: ZipArchiveMode.Create, true, Encoding.UTF8, isUpdateMode: false); try { diff --git a/src/MiniExcel/Utils/XmlReaderHelper.cs b/src/MiniExcel/Utils/XmlReaderHelper.cs index c660c28d..2d8cbf23 100644 --- a/src/MiniExcel/Utils/XmlReaderHelper.cs +++ b/src/MiniExcel/Utils/XmlReaderHelper.cs @@ -107,7 +107,14 @@ public static string GetAttribute(XmlReader reader, string name, params string[] [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream, [EnumeratorCancellation]CancellationToken ct = default, params string[] nss) { - using (var reader = XmlReader.Create(stream)) + var xmlSettings = GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + using (var reader = XmlReader.Create(stream, xmlSettings)) { if (!IsStartElement(reader, "sst", nss)) yield break; @@ -129,5 +136,16 @@ public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream } } } + + internal static XmlReaderSettings GetXmlReaderSettings(bool async) + { + return new XmlReaderSettings + { + IgnoreComments = true, + IgnoreWhitespace = true, + XmlResolver = null, + Async = async, + }; + } } } From e3087d7483f6f6c951482c08cb4208e5ceb39bdf Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 07:16:45 -0400 Subject: [PATCH 13/25] Rewrite all public methods to Async and eliminate the need for MiniExcel.Async.cs --- src/MiniExcel/ExcelFactory.cs | 9 ++-- src/MiniExcel/MiniExcel.Async.cs | 73 -------------------------------- src/MiniExcel/MiniExcel.cs | 59 +++++++++++++++----------- 3 files changed, 40 insertions(+), 101 deletions(-) delete mode 100644 src/MiniExcel/MiniExcel.Async.cs diff --git a/src/MiniExcel/ExcelFactory.cs b/src/MiniExcel/ExcelFactory.cs index 8f6dba31..e37ca0b6 100644 --- a/src/MiniExcel/ExcelFactory.cs +++ b/src/MiniExcel/ExcelFactory.cs @@ -5,17 +5,20 @@ using MiniExcelLibs.OpenXml.SaveByTemplate; using System; using System.IO; + using System.Threading; + using System.Threading.Tasks; - internal static class ExcelReaderFactory + internal static partial class ExcelReaderFactory { - internal static IExcelReader GetProvider(Stream stream, ExcelType excelType, IConfiguration configuration) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal static async Task GetProviderAsync(Stream stream, ExcelType excelType, IConfiguration configuration, CancellationToken ct = default) { switch (excelType) { case ExcelType.CSV: return new CsvReader(stream, configuration); case ExcelType.XLSX: - return ExcelOpenXmlSheetReader.Create(stream, configuration); + return await ExcelOpenXmlSheetReader.CreateAsync(stream, configuration, ct: ct).ConfigureAwait(false); default: throw new NotSupportedException("Something went wrong. Please report this issue you are experiencing with MiniExcel."); } diff --git a/src/MiniExcel/MiniExcel.Async.cs b/src/MiniExcel/MiniExcel.Async.cs deleted file mode 100644 index 85eaa2ae..00000000 --- a/src/MiniExcel/MiniExcel.Async.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace MiniExcelLibs -{ - using MiniExcelLibs.OpenXml; - using System; - using System.Collections; - using System.Collections.Generic; - using System.Data; - using System.IO; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using Utils; - - public static partial class MiniExcel - { - public static async Task InsertAsync(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default) - { - if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm") - throw new NotSupportedException("MiniExcel's Insert does not support the .xlsm format"); - - if (!File.Exists(path)) - { - var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, ct: cancellationToken); - return rowsWritten.FirstOrDefault(); - } - - if (excelType == ExcelType.CSV) - { - using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan)) - return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken); - } - else - { - using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan)) - return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken); - } - } - - public static async TaskInsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default) - { - stream.Seek(0, SeekOrigin.End); - // reuse code - if (excelType == ExcelType.CSV) - { - var newValue = value is IEnumerable || value is IDataReader ? value : new[]{value}.AsEnumerable(); - return await ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).InsertAsync(overwriteSheet, cancellationToken); - } - else - { - var configOrDefault = configuration ?? new OpenXmlConfiguration { FastMode = true }; - return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).InsertAsync(overwriteSheet, cancellationToken); - } - } - - /// - /// QueryAsDataTable is not recommended, because it'll load all data into memory. - /// - [Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")] - public static async Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - return await Task.Run(() => QueryAsDataTable(path, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration), cancellationToken).ConfigureAwait(false); - } - - /// - /// QueryAsDataTable is not recommended, because it'll load all data into memory. - /// - [Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")] - public static async Task QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) - { - return await Task.Run(() => QueryAsDataTable(stream, useHeaderRow, sheetName, excelType, startCell, configuration), cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index 6cad3bc4..f50a5f81 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -40,41 +40,43 @@ public static MiniExcelDataReader GetReader(this Stream stream, bool useHeaderRo return new MiniExcelDataReader(stream, useHeaderRow, sheetName, excelType, startCell, configuration); } - public static int Insert(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task InsertAsync(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken ct = default) { if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm") throw new NotSupportedException("MiniExcel's Insert does not support the .xlsm format"); if (!File.Exists(path)) { - var rowsWritten = SaveAs(path, value, printHeader, sheetName, excelType, configuration); + var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, ct: ct).ConfigureAwait(false); return rowsWritten.FirstOrDefault(); } if (excelType == ExcelType.CSV) { using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan)) - return Insert(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet); + return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, ct).ConfigureAwait(false); } else { using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan)) - return Insert(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet); + return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, ct).ConfigureAwait(false); } } - public static int Insert(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task InsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken ct = default) { stream.Seek(0, SeekOrigin.End); if (excelType == ExcelType.CSV) { var newValue = value is IEnumerable || value is IDataReader ? value : new[] { value }; - return ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).Insert(overwriteSheet); + return await ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).InsertAsync(overwriteSheet, ct).ConfigureAwait(false); } else { var configOrDefault = configuration ?? new OpenXmlConfiguration { FastMode = true }; - return ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).Insert(overwriteSheet); + return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).InsertAsync(overwriteSheet, ct).ConfigureAwait(false); } } @@ -105,7 +107,7 @@ public static async Task SaveAsAsync(this Stream stream, object value, bo [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async IAsyncEnumerable QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken ct = default) where T : class, new() { - using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) await foreach (var item in excelReader.QueryAsync(sheetName, startCell, hasHeader, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; } @@ -121,7 +123,7 @@ public static async IAsyncEnumerable QueryAsync(string path, bool useHe [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async IAsyncEnumerable QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { - using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) await foreach (var item in excelReader.QueryAsync(useHeaderRow, sheetName, startCell, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); @@ -144,32 +146,36 @@ public static async IAsyncEnumerable QueryAsync(this Stream stream, boo /// lower right corner /// /// - public static IEnumerable QueryRange(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - foreach (var item in QueryRange(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, endCell, configuration)) + await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, endCell, configuration, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; } - public static IEnumerable QueryRange(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { - using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) - foreach (var item in excelReader.QueryRange(useHeaderRow, sheetName, startCell, endCell)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startCell, endCell, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } - public static IEnumerable QueryRange(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) - foreach (var item in QueryRange(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration)) + await foreach(var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item; } - public static IEnumerable QueryRange(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) { - using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) - foreach (var item in excelReader.QueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct).WithCancellation(ct).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } @@ -229,25 +235,28 @@ public static async Task MergeSameCellsAsync(this Stream stream, byte[] filePath /// QueryAsDataTable is not recommended, because it'll load all data into memory. /// [Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")] - public static DataTable QueryAsDataTable(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async static Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) { using (var stream = FileHelper.OpenSharedRead(path)) { - return QueryAsDataTable(stream, useHeaderRow, sheetName, excelType: ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration); + return await QueryAsDataTableAsync(stream, useHeaderRow, sheetName, excelType: ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, ct).ConfigureAwait(false); } } - public static DataTable QueryAsDataTable(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async static Task QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) { if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/ - sheetName = stream.GetSheetNames(configuration as OpenXmlConfiguration).First(); + sheetName = (await stream.GetSheetNamesAsync(configuration as OpenXmlConfiguration, ct).ConfigureAwait(false)).First(); var dt = new DataTable(sheetName); var first = true; - var rows = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).Query(false, sheetName, startCell); + var provider = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false); + var rows = provider.QueryAsync(false, sheetName, startCell); var columnDict = new Dictionary(); - foreach (IDictionary row in rows) + await foreach (IDictionary row in rows.WithCancellation(ct).ConfigureAwait(false)) { if (first) { From 4a368f316e6608be925ac00f0c4f863e03605ea4 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 07:46:24 -0400 Subject: [PATCH 14/25] Expose AddPictureAsync --- src/MiniExcel/MiniExcel.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index f50a5f81..a1bf78c8 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -18,15 +18,17 @@ namespace MiniExcelLibs { public static partial class MiniExcel { - public static void AddPicture(string path, params MiniExcelPicture[] images) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task AddPictureAsync(string path, CancellationToken ct = default, params MiniExcelPicture[] images) { using (var stream = File.Open(path, FileMode.OpenOrCreate)) - MiniExcelPictureImplement.AddPicture(stream, images); + await MiniExcelPictureImplement.AddPictureAsync(stream, ct, images).ConfigureAwait(false); } - public static void AddPicture(Stream excelStream, params MiniExcelPicture[] images) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task AddPicture(Stream excelStream, CancellationToken ct = default, params MiniExcelPicture[] images) { - MiniExcelPictureImplement.AddPicture(excelStream, images); + await MiniExcelPictureImplement.AddPictureAsync(excelStream, ct, images).ConfigureAwait(false); } public static MiniExcelDataReader GetReader(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) From f3285ace9ed5eca5a162c0f6bba31b1e8610ce3a Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 09:38:47 -0400 Subject: [PATCH 15/25] Fix some diverging methods and remove sync version --- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 62 ++++++++++--------- .../OpenXml/ExcelOpenXmlSheetWriter.cs | 30 --------- .../AsyncEnumerableWriteAdapter.cs | 2 - .../IAsyncMiniExcelWriteAdapter.cs | 2 - 4 files changed, 33 insertions(+), 63 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 3f88c082..4603ad2a 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -188,7 +188,13 @@ private static async Task WriteDimensionAsync( // Async and sync diverge. Do not apply the attribute //[Zomp.SyncMethodGenerator.CreateSyncVersion] - private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, object values, CancellationToken cancellationToken) + private async Task WriteValuesAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + object values, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -214,22 +220,22 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje await WriteEmptySheetAsync(writer); return 0; } - var maxColumnIndex = props.Count; int maxRowIndex; + var maxColumnIndex = props.Count(x => x != null && !x.ExcelIgnore); await writer.WriteAsync(WorksheetXml.StartWorksheetWithRelationship); long dimensionPlaceholderPostition = 0; // We can write the dimensions directly if the row count is known - if (_configuration.FastMode && !isKnownCount) + if (isKnownCount) { - dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer); + maxRowIndex = _printHeader ? count + 1 : count; + await writer.WriteAsync(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, props.Count))); } - else if (isKnownCount) + else if (_configuration.FastMode) { - maxRowIndex = count + (_printHeader ? 1 : 0); - await writer.WriteAsync(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, props.Count))); + dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer); } //sheet view @@ -240,7 +246,7 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje long columnWidthsPlaceholderPosition = 0; if (_configuration.EnableAutoWidth) { - columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, props); + columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, maxColumnIndex); widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props); } else @@ -289,10 +295,8 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje } } #endif - maxRowIndex = currentRowIndex; - await writer.WriteAsync(WorksheetXml.Drawing(_currentSheetIndex)); await writer.WriteAsync(WorksheetXml.EndSheetData); if (_configuration.AutoFilter) @@ -300,6 +304,7 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje await writer.WriteAsync(WorksheetXml.Autofilter(GetDimensionRef(maxRowIndex, maxColumnIndex))); } + await writer.WriteAsync(WorksheetXml.Drawing(_currentSheetIndex)); await writer.WriteAsync(WorksheetXml.EndWorksheet); if (_configuration.FastMode && dimensionPlaceholderPostition != 0) @@ -308,25 +313,26 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje } if (_configuration.EnableAutoWidth) { - await OverwriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns, cancellationToken); + await OverwriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths?.Columns, cancellationToken); } - var toSubtract = _printHeader ? 1 : 0; - return maxRowIndex - toSubtract; + if (_printHeader) + maxRowIndex--; + + return maxRowIndex; } - // Async and sync diverge. Do not apply the attribute - //[Zomp.SyncMethodGenerator.CreateSyncVersion] + [Zomp.SyncMethodGenerator.CreateSyncVersion] private static async Task WriteColumnWidthPlaceholdersAsync( #if SYNC_ONLY global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, #else MiniExcelAsyncStreamWriter writer, #endif - ICollection props) + int count) { var placeholderPosition = await writer.FlushAsync(); - await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(props.Count)); + await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(count)); return placeholderPosition; } @@ -378,8 +384,7 @@ private static async Task WriteColumnsWidthsAsync( await writer.WriteAsync(WorksheetXml.EndCols); } - // Async and sync diverge. Do not apply the attribute - //[Zomp.SyncMethodGenerator.CreateSyncVersion] + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task PrintHeaderAsync( #if SYNC_ONLY global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, @@ -388,22 +393,21 @@ private async Task PrintHeaderAsync( #endif List props, CancellationToken cancellationToken = default) { - var xIndex = 1; - var yIndex = 1; + const int yIndex = 1; await writer.WriteAsync(WorksheetXml.StartRow(yIndex)); + var xIndex = 1; foreach (var p in props) { - cancellationToken.ThrowIfCancellationRequested(); - - if (p == null) + //reason : https://github.com/mini-software/MiniExcel/issues/142 + if (p != null) { - xIndex++; //reason : https://github.com/mini-software/MiniExcel/issues/142 - continue; - } + if (p.ExcelIgnore) + continue; - var r = ExcelOpenXmlUtils.ConvertXyToCell(xIndex, yIndex); - await WriteCellAsync(writer, r, columnName: p.ExcelColumnName); + var r = ExcelOpenXmlUtils.ConvertXyToCell(xIndex, yIndex); + await WriteCellAsync(writer, r, columnName: p.ExcelColumnName); + } xIndex++; } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index 1fcc64a7..5a88c85f 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -160,36 +160,6 @@ private int WriteValues(MiniExcelStreamWriter writer, object values) return maxRowIndex; } - private static long WriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, int count) - { - var placeholderPosition = writer.Flush(); - writer.WriteWhitespace(WorksheetXml.GetColumnPlaceholderLength(count)); - return placeholderPosition; - } - - private void PrintHeader(MiniExcelStreamWriter writer, List props) - { - const int yIndex = 1; - writer.Write(WorksheetXml.StartRow(yIndex)); - - var xIndex = 1; - foreach (var p in props) - { - //reason : https://github.com/mini-software/MiniExcel/issues/142 - if (p != null) - { - if (p.ExcelIgnore) - continue; - - var r = ExcelOpenXmlUtils.ConvertXyToCell(xIndex, yIndex); - WriteCell(writer, r, columnName: p.ExcelColumnName); - } - xIndex++; - } - - writer.Write(WorksheetXml.EndRow); - } - private void CreateZipEntry(string path, string contentType, string content) { ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest); diff --git a/src/MiniExcel/WriteAdapter/AsyncEnumerableWriteAdapter.cs b/src/MiniExcel/WriteAdapter/AsyncEnumerableWriteAdapter.cs index 5c8811a7..805c84f6 100644 --- a/src/MiniExcel/WriteAdapter/AsyncEnumerableWriteAdapter.cs +++ b/src/MiniExcel/WriteAdapter/AsyncEnumerableWriteAdapter.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; -#if NETSTANDARD2_0_OR_GREATER || NET namespace MiniExcelLibs.WriteAdapter { internal class AsyncEnumerableWriteAdapter : IAsyncMiniExcelWriteAdapter @@ -92,4 +91,3 @@ public async static IAsyncEnumerable GetRowValuesAsync(T currentV } } } -#endif \ No newline at end of file diff --git a/src/MiniExcel/WriteAdapter/IAsyncMiniExcelWriteAdapter.cs b/src/MiniExcel/WriteAdapter/IAsyncMiniExcelWriteAdapter.cs index ce417bf1..0e23d5cc 100644 --- a/src/MiniExcel/WriteAdapter/IAsyncMiniExcelWriteAdapter.cs +++ b/src/MiniExcel/WriteAdapter/IAsyncMiniExcelWriteAdapter.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; -#if NETSTANDARD2_0_OR_GREATER || NET namespace MiniExcelLibs.WriteAdapter { internal interface IAsyncMiniExcelWriteAdapter @@ -13,4 +12,3 @@ internal interface IAsyncMiniExcelWriteAdapter IAsyncEnumerable> GetRowsAsync(List props, CancellationToken cancellationToken); } } -#endif From 81288223676aa5c98b5c326272ef2c972c6d4d5f Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 10:13:07 -0400 Subject: [PATCH 16/25] Remove preprocessor directives made unnecessary by NET462 upgrade --- src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 10 ---------- src/MiniExcel/Utils/TypeHelper.cs | 2 -- .../WriteAdapter/MiniExcelDataReaderWriteAdapter.cs | 2 -- .../WriteAdapter/MiniExcelWriteAdapterFactory.cs | 2 -- 4 files changed, 16 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 4603ad2a..7192b263 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -198,7 +198,6 @@ private async Task WriteValuesAsync( { cancellationToken.ThrowIfCancellationRequested(); -#if NETSTANDARD2_0_OR_GREATER || NET IMiniExcelWriteAdapter writeAdapter = null; if (!MiniExcelWriteAdapterFactory.TryGetAsyncWriteAdapter(values, _configuration, out var asyncWriteAdapter)) { @@ -208,13 +207,6 @@ private async Task WriteValuesAsync( var count = 0; var isKnownCount = writeAdapter != null && writeAdapter.TryGetKnownCount(out count); var props = writeAdapter != null ? writeAdapter?.GetColumns() : await asyncWriteAdapter.GetColumnsAsync(); -#else - IMiniExcelWriteAdapter writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration); - - var isKnownCount = writeAdapter.TryGetKnownCount(out var count); - var props = writeAdapter.GetColumns(); -#endif - if (props == null) { await WriteEmptySheetAsync(writer); @@ -278,7 +270,6 @@ private async Task WriteValuesAsync( await writer.WriteAsync(WorksheetXml.EndRow); } } -#if NETSTANDARD2_0_OR_GREATER || NET else { await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken)) @@ -294,7 +285,6 @@ private async Task WriteValuesAsync( await writer.WriteAsync(WorksheetXml.EndRow); } } -#endif maxRowIndex = currentRowIndex; await writer.WriteAsync(WorksheetXml.EndSheetData); diff --git a/src/MiniExcel/Utils/TypeHelper.cs b/src/MiniExcel/Utils/TypeHelper.cs index 0873c9a5..33ae59eb 100644 --- a/src/MiniExcel/Utils/TypeHelper.cs +++ b/src/MiniExcel/Utils/TypeHelper.cs @@ -229,7 +229,6 @@ public static bool IsNumericType(Type type, bool isNullableUnderlyingType = fals return newValue; } -#if NETSTANDARD2_0_OR_GREATER || NET public static bool IsAsyncEnumerable(this Type type, out Type genericArgument) { var asyncEnumrableInterfaceType = type @@ -238,6 +237,5 @@ public static bool IsAsyncEnumerable(this Type type, out Type genericArgument) genericArgument = asyncEnumrableInterfaceType?.GetGenericArguments().FirstOrDefault(); return genericArgument != null; } -#endif } } diff --git a/src/MiniExcel/WriteAdapter/MiniExcelDataReaderWriteAdapter.cs b/src/MiniExcel/WriteAdapter/MiniExcelDataReaderWriteAdapter.cs index 8e800f63..3114eb43 100644 --- a/src/MiniExcel/WriteAdapter/MiniExcelDataReaderWriteAdapter.cs +++ b/src/MiniExcel/WriteAdapter/MiniExcelDataReaderWriteAdapter.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; -#if NETSTANDARD2_0_OR_GREATER || NET namespace MiniExcelLibs.WriteAdapter { internal class MiniExcelDataReaderWriteAdapter : IAsyncMiniExcelWriteAdapter @@ -75,4 +74,3 @@ private async IAsyncEnumerable GetRowValuesAsync(List Date: Sun, 15 Jun 2025 10:37:14 -0400 Subject: [PATCH 17/25] Remove WriteValues for WriteValuesAsync. Do the best to account for divergence, more work might be needed. --- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 12 ++- .../OpenXml/ExcelOpenXmlSheetWriter.cs | 89 ------------------- 2 files changed, 9 insertions(+), 92 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 7192b263..bb929499 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -186,8 +186,7 @@ private static async Task WriteDimensionAsync( writer.SetPosition(position); } - // Async and sync diverge. Do not apply the attribute - //[Zomp.SyncMethodGenerator.CreateSyncVersion] + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task WriteValuesAsync( #if SYNC_ONLY global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, @@ -206,7 +205,12 @@ private async Task WriteValuesAsync( var count = 0; var isKnownCount = writeAdapter != null && writeAdapter.TryGetKnownCount(out count); - var props = writeAdapter != null ? writeAdapter?.GetColumns() : await asyncWriteAdapter.GetColumnsAsync(); + List props; +#if SYNC_ONLY + props = writeAdapter?.GetColumns(); +#else + props = writeAdapter != null ? writeAdapter?.GetColumns() : await asyncWriteAdapter.GetColumnsAsync(); +#endif if (props == null) { await WriteEmptySheetAsync(writer); @@ -272,6 +276,7 @@ private async Task WriteValuesAsync( } else { +#if !SYNC_ONLY await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); @@ -284,6 +289,7 @@ private async Task WriteValuesAsync( } await writer.WriteAsync(WorksheetXml.EndRow); } +#endif } maxRowIndex = currentRowIndex; diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index 5a88c85f..679f628b 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -71,95 +71,6 @@ private static void WriteEmptySheet(MiniExcelStreamWriter writer) writer.Write(ExcelXml.EmptySheetXml); } - private int WriteValues(MiniExcelStreamWriter writer, object values) - { - var writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration); - - var isKnownCount = writeAdapter.TryGetKnownCount(out var count); - var props = writeAdapter.GetColumns(); - if (props == null) - { - WriteEmptySheet(writer); - return 0; - } - - int maxRowIndex; - var maxColumnIndex = props.Count(x => x != null && !x.ExcelIgnore); - - writer.Write(WorksheetXml.StartWorksheetWithRelationship); - - long dimensionPlaceholderPostition = 0; - - // We can write the dimensions directly if the row count is known - if (isKnownCount) - { - maxRowIndex = _printHeader ? count + 1 : count; - writer.Write(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, maxColumnIndex))); - } - else if (_configuration.FastMode) - { - dimensionPlaceholderPostition = WriteDimensionPlaceholder(writer); - } - - //sheet view - writer.Write(GetSheetViews()); - - //cols:width - ExcelWidthCollection widths = null; - long columnWidthsPlaceholderPosition = 0; - if (_configuration.EnableAutoWidth) - { - columnWidthsPlaceholderPosition = WriteColumnWidthPlaceholders(writer, maxColumnIndex); - widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props); - } - else - { - WriteColumnsWidths(writer, ExcelColumnWidth.FromProps(props)); - } - - //header - writer.Write(WorksheetXml.StartSheetData); - var currentRowIndex = 0; - if (_printHeader) - { - PrintHeader(writer, props); - currentRowIndex++; - } - - foreach (var row in writeAdapter.GetRows(props)) - { - writer.Write(WorksheetXml.StartRow(++currentRowIndex)); - foreach (var cellValue in row) - { - WriteCell(writer, currentRowIndex, cellValue.CellIndex, cellValue.Value, cellValue.Prop, widths); - } - writer.Write(WorksheetXml.EndRow); - } - maxRowIndex = currentRowIndex; - - writer.Write(WorksheetXml.EndSheetData); - - if (_configuration.AutoFilter) - writer.Write(WorksheetXml.Autofilter(GetDimensionRef(maxRowIndex, maxColumnIndex))); - - writer.Write(WorksheetXml.Drawing(_currentSheetIndex)); - writer.Write(WorksheetXml.EndWorksheet); - - if (_configuration.FastMode && dimensionPlaceholderPostition != 0) - { - WriteDimension(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition); - } - if (_configuration.EnableAutoWidth) - { - OverwriteColumnWidthPlaceholders(writer, columnWidthsPlaceholderPosition, widths?.Columns); - } - - if (_printHeader) - maxRowIndex--; - - return maxRowIndex; - } - private void CreateZipEntry(string path, string contentType, string content) { ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest); From 3c176a915ec39b1351eb39bdd00d6c8f00912aa6 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 11:03:28 -0400 Subject: [PATCH 18/25] Change ct to cancellationToken everywhere --- src/MiniExcel/Csv/CsvReader.cs | 28 +-- src/MiniExcel/ExcelFactory.cs | 4 +- src/MiniExcel/MiniExcel.cs | 162 +++++++++--------- .../OpenXml/ExcelOpenXmlSheetReader.cs | 134 +++++++-------- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 2 +- .../Picture/MiniExcelPictureImplement.cs | 6 +- .../ExcelOpenXmlTemplate.Impl.cs | 32 ++-- .../ExcelOpenXmlTemplate.MergeCells.cs | 16 +- .../SaveByTemplate/ExcelOpenXmlTemplate.cs | 18 +- src/MiniExcel/Utils/StringHelper.cs | 18 +- src/MiniExcel/Utils/XmlReaderHelper.cs | 32 ++-- src/MiniExcel/Utils/calChainHelper.cs | 2 +- .../MiniExcelOpenXmlAsyncTests.cs | 4 +- .../MiniExcelTemplateAsyncTests.cs | 2 +- 14 files changed, 230 insertions(+), 230 deletions(-) diff --git a/src/MiniExcel/Csv/CsvReader.cs b/src/MiniExcel/Csv/CsvReader.cs index 6501023b..07ef95ea 100644 --- a/src/MiniExcel/Csv/CsvReader.cs +++ b/src/MiniExcel/Csv/CsvReader.cs @@ -24,7 +24,7 @@ public CsvReader(Stream stream, IConfiguration configuration) } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public async IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, [EnumeratorCancellation] CancellationToken ct = default) + public async IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, [EnumeratorCancellation] CancellationToken cancellationToken = default) { if (startCell != "A1") throw new NotImplementedException("CSV does not implement parameter startCell"); @@ -39,7 +39,7 @@ public async IAsyncEnumerable> QueryAsync(bool useHe string row; for (var rowIndex = 1; (row = await reader.ReadLineAsync( #if NET7_0_OR_GREATER -ct +cancellationToken #endif ).ConfigureAwait(false)) != null; rowIndex++) { @@ -50,7 +50,7 @@ public async IAsyncEnumerable> QueryAsync(bool useHe { var nextPart = await reader.ReadLineAsync( #if NET7_0_OR_GREATER -ct +cancellationToken #endif ).ConfigureAwait(false); if (nextPart == null) @@ -118,36 +118,36 @@ public async IAsyncEnumerable> QueryAsync(bool useHe } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken ct = default) where T : class, new() + public IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { - var dynamicRecords = QueryAsync(false, sheetName, startCell, ct); - return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, _config, ct); + var dynamicRecords = QueryAsync(false, sheetName, startCell, cancellationToken); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, _config, cancellationToken); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken ct = default) + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default) { throw new NotImplementedException("CSV does not implement QueryRange"); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken ct = default) where T : class, new() + public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { - var dynamicRecords = QueryRangeAsync(false, sheetName, startCell, endCell, ct); - return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, this._config, ct); + var dynamicRecords = QueryRangeAsync(false, sheetName, startCell, endCell, cancellationToken); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, this._config, cancellationToken); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken ct = default) + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default) { throw new NotImplementedException("CSV does not implement QueryRange"); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken ct = default) where T : class, new() + public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { - var dynamicRecords = QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct); - return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, ReferenceHelper.ConvertXyToCell(startRowIndex, startColumnIndex), hasHeader, this._config, ct); + var dynamicRecords = QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, ReferenceHelper.ConvertXyToCell(startRowIndex, startColumnIndex), hasHeader, this._config, cancellationToken); } private string[] Split(string row) diff --git a/src/MiniExcel/ExcelFactory.cs b/src/MiniExcel/ExcelFactory.cs index e37ca0b6..a07b4d3d 100644 --- a/src/MiniExcel/ExcelFactory.cs +++ b/src/MiniExcel/ExcelFactory.cs @@ -11,14 +11,14 @@ internal static partial class ExcelReaderFactory { [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal static async Task GetProviderAsync(Stream stream, ExcelType excelType, IConfiguration configuration, CancellationToken ct = default) + internal static async Task GetProviderAsync(Stream stream, ExcelType excelType, IConfiguration configuration, CancellationToken cancellationToken = default) { switch (excelType) { case ExcelType.CSV: return new CsvReader(stream, configuration); case ExcelType.XLSX: - return await ExcelOpenXmlSheetReader.CreateAsync(stream, configuration, ct: ct).ConfigureAwait(false); + return await ExcelOpenXmlSheetReader.CreateAsync(stream, configuration, cancellationToken: cancellationToken).ConfigureAwait(false); default: throw new NotSupportedException("Something went wrong. Please report this issue you are experiencing with MiniExcel."); } diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index a1bf78c8..b0b63fdf 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -19,16 +19,16 @@ namespace MiniExcelLibs public static partial class MiniExcel { [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task AddPictureAsync(string path, CancellationToken ct = default, params MiniExcelPicture[] images) + public static async Task AddPictureAsync(string path, CancellationToken cancellationToken = default, params MiniExcelPicture[] images) { using (var stream = File.Open(path, FileMode.OpenOrCreate)) - await MiniExcelPictureImplement.AddPictureAsync(stream, ct, images).ConfigureAwait(false); + await MiniExcelPictureImplement.AddPictureAsync(stream, cancellationToken, images).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task AddPicture(Stream excelStream, CancellationToken ct = default, params MiniExcelPicture[] images) + public static async Task AddPicture(Stream excelStream, CancellationToken cancellationToken = default, params MiniExcelPicture[] images) { - await MiniExcelPictureImplement.AddPictureAsync(excelStream, ct, images).ConfigureAwait(false); + await MiniExcelPictureImplement.AddPictureAsync(excelStream, cancellationToken, images).ConfigureAwait(false); } public static MiniExcelDataReader GetReader(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) @@ -43,90 +43,90 @@ public static MiniExcelDataReader GetReader(this Stream stream, bool useHeaderRo } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task InsertAsync(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken ct = default) + public static async Task InsertAsync(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default) { if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm") throw new NotSupportedException("MiniExcel's Insert does not support the .xlsm format"); if (!File.Exists(path)) { - var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, ct: ct).ConfigureAwait(false); + var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, cancellationToken: cancellationToken).ConfigureAwait(false); return rowsWritten.FirstOrDefault(); } if (excelType == ExcelType.CSV) { using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan)) - return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, ct).ConfigureAwait(false); + return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken).ConfigureAwait(false); } else { using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan)) - return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, ct).ConfigureAwait(false); + return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken).ConfigureAwait(false); } } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task InsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken ct = default) + public static async Task InsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default) { stream.Seek(0, SeekOrigin.End); if (excelType == ExcelType.CSV) { var newValue = value is IEnumerable || value is IDataReader ? value : new[] { value }; - return await ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).InsertAsync(overwriteSheet, ct).ConfigureAwait(false); + return await ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).InsertAsync(overwriteSheet, cancellationToken).ConfigureAwait(false); } else { var configOrDefault = configuration ?? new OpenXmlConfiguration { FastMode = true }; - return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).InsertAsync(overwriteSheet, ct).ConfigureAwait(false); + return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).InsertAsync(overwriteSheet, cancellationToken).ConfigureAwait(false); } } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false, CancellationToken ct = default) + public static async Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false, CancellationToken cancellationToken = default) { if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm") throw new NotSupportedException("MiniExcel's SaveAs does not support the .xlsm format"); using (var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew)) - return await SaveAsAsync(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, ct).ConfigureAwait(false); + return await SaveAsAsync(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default) { - return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(ct).ConfigureAwait(false); + return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken ct = default) where T : class, new() + public static async IAsyncEnumerable QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new() { using (var stream = FileHelper.OpenSharedRead(path)) - await foreach (var item in QueryAsync(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, hasHeader, ct).WithCancellation(ct).ConfigureAwait(false)) + await foreach (var item in QueryAsync(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, hasHeader, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item; //Foreach yield return twice reason : https://stackoverflow.com/questions/66791982/ienumerable-extract-code-lazy-loading-show-stream-was-not-readable } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken ct = default) where T : class, new() + public static async IAsyncEnumerable QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new() { - using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) - await foreach (var item in excelReader.QueryAsync(sheetName, startCell, hasHeader, ct).WithCancellation(ct).ConfigureAwait(false)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryAsync(sheetName, startCell, hasHeader, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item; } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) + public static async IAsyncEnumerable QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - await foreach (var item in QueryAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, ct).WithCancellation(ct).ConfigureAwait(false)) + await foreach (var item in QueryAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item; } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) + public static async IAsyncEnumerable QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) - await foreach (var item in excelReader.QueryAsync(useHeaderRow, sheetName, startCell, ct).WithCancellation(ct).ConfigureAwait(false)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryAsync(useHeaderRow, sheetName, startCell, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } @@ -149,35 +149,35 @@ public static async IAsyncEnumerable QueryAsync(this Stream stream, boo /// /// [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) + public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, endCell, configuration, ct).WithCancellation(ct).ConfigureAwait(false)) + await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, endCell, configuration, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item; } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) + public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) - await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startCell, endCell, ct).WithCancellation(ct).ConfigureAwait(false)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startCell, endCell, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) + public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - await foreach(var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration, ct).WithCancellation(ct).ConfigureAwait(false)) + await foreach(var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item; } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken ct = default) + public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false)) - await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct).WithCancellation(ct).ConfigureAwait(false)) + using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } @@ -185,50 +185,50 @@ public static async IAsyncEnumerable QueryRangeAsync(this Stream stream #endregion QueryRange [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) { using (var stream = File.Create(path)) - await SaveAsByTemplateAsync(stream, templatePath, value, configuration, ct); + await SaveAsByTemplateAsync(stream, templatePath, value, configuration, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) { using (var stream = File.Create(path)) - await SaveAsByTemplateAsync(stream, templateBytes, value, configuration, ct); + await SaveAsByTemplateAsync(stream, templateBytes, value, configuration, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) { - await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, ct); + await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default) { - await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, ct); + await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, cancellationToken).ConfigureAwait(false); } #region MergeCells [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task MergeSameCellsAsync(string mergedFilePath, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task MergeSameCellsAsync(string mergedFilePath, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default) { using (var stream = File.Create(mergedFilePath)) - await MergeSameCellsAsync(stream, path, excelType, configuration, ct).ConfigureAwait(false); + await MergeSameCellsAsync(stream, path, excelType, configuration, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task MergeSameCellsAsync(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task MergeSameCellsAsync(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default) { - await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, ct).ConfigureAwait(false); + await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task MergeSameCellsAsync(this Stream stream, byte[] filePath, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken ct = default) + public static async Task MergeSameCellsAsync(this Stream stream, byte[] filePath, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default) { - await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(filePath, ct).ConfigureAwait(false); + await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(filePath, cancellationToken).ConfigureAwait(false); } #endregion @@ -238,27 +238,27 @@ public static async Task MergeSameCellsAsync(this Stream stream, byte[] filePath /// [Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")] [Zomp.SyncMethodGenerator.CreateSyncVersion] - public async static Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) + public async static Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) { - return await QueryAsDataTableAsync(stream, useHeaderRow, sheetName, excelType: ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, ct).ConfigureAwait(false); + return await QueryAsDataTableAsync(stream, useHeaderRow, sheetName, excelType: ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, cancellationToken).ConfigureAwait(false); } } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public async static Task QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) + public async static Task QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) { if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/ - sheetName = (await stream.GetSheetNamesAsync(configuration as OpenXmlConfiguration, ct).ConfigureAwait(false)).First(); + sheetName = (await stream.GetSheetNamesAsync(configuration as OpenXmlConfiguration, cancellationToken).ConfigureAwait(false)).First(); var dt = new DataTable(sheetName); var first = true; - var provider = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, ct).ConfigureAwait(false); + var provider = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false); var rows = provider.QueryAsync(false, sheetName, startCell); var columnDict = new Dictionary(); - await foreach (IDictionary row in rows.WithCancellation(ct).ConfigureAwait(false)) + await foreach (IDictionary row in rows.WithCancellation(cancellationToken).ConfigureAwait(false)) { if (first) { @@ -294,52 +294,52 @@ public async static Task QueryAsDataTableAsync(this Stream stream, bo } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetSheetNamesAsync(string path, OpenXmlConfiguration config = null, CancellationToken ct = default) + public static async Task> GetSheetNamesAsync(string path, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return await GetSheetNamesAsync(stream, config, ct); + return await GetSheetNamesAsync(stream, config, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetSheetNamesAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken ct = default) + public static async Task> GetSheetNamesAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default) { config = config ?? OpenXmlConfiguration.DefaultConfig; var archive = new ExcelOpenXmlZip(stream); - var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, ct: ct).ConfigureAwait(false); - var rels = await reader.GetWorkbookRelsAsync(archive.entries, ct).ConfigureAwait(false); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, cancellationToken: cancellationToken).ConfigureAwait(false); + var rels = await reader.GetWorkbookRelsAsync(archive.entries, cancellationToken).ConfigureAwait(false); return rels.Select(s => s.Name).ToList(); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetSheetInformationsAsync(string path, OpenXmlConfiguration config = null, CancellationToken ct = default) + public static async Task> GetSheetInformationsAsync(string path, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return await GetSheetInformationsAsync(stream, config, ct).ConfigureAwait(false); + return await GetSheetInformationsAsync(stream, config, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetSheetInformationsAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken ct = default) + public static async Task> GetSheetInformationsAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default) { config = config ?? OpenXmlConfiguration.DefaultConfig; var archive = new ExcelOpenXmlZip(stream); - var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, ct: ct).ConfigureAwait(false); - var rels = await reader.GetWorkbookRelsAsync(archive.entries, ct).ConfigureAwait(false); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, cancellationToken: cancellationToken).ConfigureAwait(false); + var rels = await reader.GetWorkbookRelsAsync(archive.entries, cancellationToken).ConfigureAwait(false); return rels.Select((s, i) => s.ToSheetInfo((uint)i)).ToList(); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetColumnsAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) + public static async Task> GetColumnsAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return await GetColumnsAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration, ct).ConfigureAwait(false); + return await GetColumnsAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetColumnsAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken ct = default) + public static async Task> GetColumnsAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) { - var enumerator = QueryAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration).GetAsyncEnumerator(ct); + var enumerator = QueryAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration).GetAsyncEnumerator(cancellationToken); _ = enumerator.ConfigureAwait(false); if (!await enumerator.MoveNextAsync()) { @@ -349,49 +349,49 @@ public static async Task> GetColumnsAsync(this Stream stream } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetSheetDimensionsAsync(string path, CancellationToken ct = default) + public static async Task> GetSheetDimensionsAsync(string path, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return await GetSheetDimensionsAsync(stream, ct).ConfigureAwait(false); + return await GetSheetDimensionsAsync(stream, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task> GetSheetDimensionsAsync(this Stream stream, CancellationToken ct = default) + public static async Task> GetSheetDimensionsAsync(this Stream stream, CancellationToken cancellationToken = default) { - var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, null, ct: ct).ConfigureAwait(false); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, null, cancellationToken: cancellationToken).ConfigureAwait(false); return reader.GetDimensions(); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task ConvertCsvToXlsxAsync(string csv, string xlsx, CancellationToken ct = default) + public static async Task ConvertCsvToXlsxAsync(string csv, string xlsx, CancellationToken cancellationToken = default) { using (var csvStream = FileHelper.OpenSharedRead(csv)) using (var xlsxStream = new FileStream(xlsx, FileMode.CreateNew)) { - await ConvertCsvToXlsxAsync(csvStream, xlsxStream, ct: ct).ConfigureAwait(false); + await ConvertCsvToXlsxAsync(csvStream, xlsxStream, cancellationToken: cancellationToken).ConfigureAwait(false); } } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task ConvertCsvToXlsxAsync(Stream csv, Stream xlsx, CancellationToken ct = default) + public static async Task ConvertCsvToXlsxAsync(Stream csv, Stream xlsx, CancellationToken cancellationToken = default) { var value = QueryAsync(csv, useHeaderRow: false, excelType: ExcelType.CSV); - await SaveAsAsync(xlsx, value, printHeader: false, excelType: ExcelType.XLSX, ct: ct).ConfigureAwait(false); + await SaveAsAsync(xlsx, value, printHeader: false, excelType: ExcelType.XLSX, cancellationToken: cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task ConvertXlsxToCsvAsync(string xlsx, string csv, CancellationToken ct = default) + public static async Task ConvertXlsxToCsvAsync(string xlsx, string csv, CancellationToken cancellationToken = default) { using (var xlsxStream = FileHelper.OpenSharedRead(xlsx)) using (var csvStream = new FileStream(csv, FileMode.CreateNew)) - await ConvertXlsxToCsvAsync(xlsxStream, csvStream, ct).ConfigureAwait(false); + await ConvertXlsxToCsvAsync(xlsxStream, csvStream, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task ConvertXlsxToCsvAsync(Stream xlsx, Stream csv, CancellationToken ct = default) + public static async Task ConvertXlsxToCsvAsync(Stream xlsx, Stream csv, CancellationToken cancellationToken = default) { var value = Query(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX); - await SaveAsAsync(csv, value, printHeader: false, excelType: ExcelType.CSV, ct: ct).ConfigureAwait(false); + await SaveAsAsync(csv, value, printHeader: false, excelType: ExcelType.CSV, cancellationToken: cancellationToken).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs index b37b3b6e..f74e9050 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs @@ -34,32 +34,32 @@ private ExcelOpenXmlSheetReader(Stream stream, IConfiguration configuration, boo } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task CreateAsync(Stream stream, IConfiguration configuration, bool isUpdateMode = true, CancellationToken ct = default) + public static async Task CreateAsync(Stream stream, IConfiguration configuration, bool isUpdateMode = true, CancellationToken cancellationToken = default) { var reader = new ExcelOpenXmlSheetReader(stream, configuration, isUpdateMode); - await reader.SetSharedStringsAsync(ct).ConfigureAwait(false); + await reader.SetSharedStringsAsync(cancellationToken).ConfigureAwait(false); return reader; } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken ct = default) + public IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default) { - return QueryRangeAsync(useHeaderRow, sheetName, startCell, "", ct); + return QueryRangeAsync(useHeaderRow, sheetName, startCell, "", cancellationToken); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken ct = default) where T : class, new() + public IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { if (sheetName == null) sheetName = CustomPropertyHelper.GetExcellSheetInfo(typeof(T), _config)?.ExcelSheetName; //Todo: Find a way if possible to remove the 'hasHeader' parameter to check whether or not to include // the first row in the result set in favor of modifying the already present 'useHeaderRow' to do the same job - return QueryImplAsync(QueryAsync(false, sheetName, startCell, ct), startCell, hasHeader, _config); + return QueryImplAsync(QueryAsync(false, sheetName, startCell, cancellationToken), startCell, hasHeader, _config); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken ct = default) + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default) { if (!ReferenceHelper.ParseReference(startCell, out var startColumnIndex, out var startRowIndex)) { @@ -84,17 +84,17 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea endRowIndex = rIndex - 1; } - return InternalQueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct); + return InternalQueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken ct = default) where T : class, new() + public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { - return QueryImplAsync(QueryRangeAsync(false, sheetName, startCell, endCell, ct), startCell, hasHeader, this._config); + return QueryImplAsync(QueryRangeAsync(false, sheetName, startCell, endCell, cancellationToken), startCell, hasHeader, this._config); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken ct = default) + public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default) { if (startRowIndex <= 0) { @@ -127,18 +127,18 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea endColumnIndex--; } - return InternalQueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct); + return InternalQueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken ct = default) where T : class, new() + public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { - return QueryImplAsync(QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, ct), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config); + return QueryImplAsync(QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal async IAsyncEnumerable> InternalQueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, [EnumeratorCancellation] CancellationToken ct = default) + internal async IAsyncEnumerable> InternalQueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, [EnumeratorCancellation] CancellationToken cancellationToken = default) { var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY @@ -153,7 +153,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA // TODO: need to optimize performance // Q. why need 3 times openstream merge one open read? A. no, zipstream can't use position = 0 - var mergeCellsResult = await TryGetMergeCellsAsync(sheetEntry, ct).ConfigureAwait(false); + var mergeCellsResult = await TryGetMergeCellsAsync(sheetEntry, cancellationToken).ConfigureAwait(false); if (_config.FillMergedCells && !mergeCellsResult.IsSuccess) { yield break; @@ -161,7 +161,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA _mergeCells = mergeCellsResult.MergeCells; - var maxRowColumnIndexResult = await TryGetMaxRowColumnIndexAsync(sheetEntry, ct).ConfigureAwait(false); + var maxRowColumnIndexResult = await TryGetMaxRowColumnIndexAsync(sheetEntry, cancellationToken).ConfigureAwait(false); if (!maxRowColumnIndexResult.IsSuccess) { yield break; @@ -182,14 +182,14 @@ internal async IAsyncEnumerable> InternalQueryRangeA if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) yield break; - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) yield break; while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; var headRows = new Dictionary(); @@ -207,8 +207,8 @@ internal async IAsyncEnumerable> InternalQueryRangeA if (rowIndex < startRowIndex) { - await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false); - await XmlReaderHelper.SkipToNextSameLevelDomAsync(reader, ct).ConfigureAwait(false); + await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false); + await XmlReaderHelper.SkipToNextSameLevelDomAsync(reader, cancellationToken).ConfigureAwait(false); continue; } if (endRowIndex.HasValue && rowIndex > endRowIndex.Value) @@ -230,7 +230,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA } // row -> c, must after `if (nextRowIndex < rowIndex)` condition code, eg. The first empty row has no xml element,and the second row xml element is - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false) && !_config.IgnoreEmptyRows) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false) && !_config.IgnoreEmptyRows) { //Fill in case of self closed empty row tag eg. yield return GetCell(useHeaderRow, maxColumnIndex, headRows, startColumnIndex); @@ -249,7 +249,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA var aR = reader.GetAttribute("r"); var aT = reader.GetAttribute("t"); var cellAndColumn = await ReadCellAndSetColumnIndexAsync(reader, columnIndex, withoutCR, - startColumnIndex, aR, aT, ct).ConfigureAwait(false); + startColumnIndex, aR, aT, cancellationToken).ConfigureAwait(false); var cellValue = cellAndColumn.CellValue; columnIndex = cellAndColumn.ColumnIndex; @@ -300,13 +300,13 @@ internal async IAsyncEnumerable> InternalQueryRangeA yield return cell; } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -315,7 +315,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable QueryImplAsync(IAsyncEnumerable> values, string startCell, bool hasHeader, Configuration configuration, [EnumeratorCancellation] CancellationToken ct = default) where T : class, new() + public static async IAsyncEnumerable QueryImplAsync(IAsyncEnumerable> values, string startCell, bool hasHeader, Configuration configuration, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new() { var type = typeof(T); @@ -326,7 +326,7 @@ internal async IAsyncEnumerable> InternalQueryRangeA var first = true; var rowIndex = 0; - await foreach (var item in values.WithCancellation(ct).ConfigureAwait(false)) + await foreach (var item in values.WithCancellation(cancellationToken).ConfigureAwait(false)) { if (first) { @@ -447,7 +447,7 @@ private static void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, } [Zomp.SyncMethodGenerator.CreateSyncVersion] - private async Task SetSharedStringsAsync(CancellationToken ct = default) + private async Task SetSharedStringsAsync(CancellationToken cancellationToken = default) { if (_sharedStrings != null) return; @@ -460,13 +460,13 @@ private async Task SetSharedStringsAsync(CancellationToken ct = default) if (_config.EnableSharedStringCache && sharedStringsEntry.Length >= _config.SharedStringCacheSize) { _sharedStrings = new SharedStringsDiskCache(); - await foreach (var sharedString in XmlReaderHelper.GetSharedStringsAsync(stream, ct, _ns).WithCancellation(ct).ConfigureAwait(false)) + await foreach (var sharedString in XmlReaderHelper.GetSharedStringsAsync(stream, cancellationToken, _ns).WithCancellation(cancellationToken).ConfigureAwait(false)) _sharedStrings[idx++] = sharedString; } else if (_sharedStrings == null) { var list = new List(); - await foreach (var str in XmlReaderHelper.GetSharedStringsAsync(stream, ct, _ns).WithCancellation(ct).ConfigureAwait(false)) + await foreach (var str in XmlReaderHelper.GetSharedStringsAsync(stream, cancellationToken, _ns).WithCancellation(cancellationToken).ConfigureAwait(false)) { list.Add(str); } @@ -483,7 +483,7 @@ private void SetWorkbookRels(ReadOnlyCollection entries) } [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCollection entries, [EnumeratorCancellation] CancellationToken ct = default) + internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCollection entries, [EnumeratorCancellation] CancellationToken cancellationToken = default) { var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY @@ -500,7 +500,7 @@ internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCo if (!XmlReaderHelper.IsStartElement(reader, "workbook", _ns)) yield break; - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) yield break; var activeSheetIndex = 0; @@ -508,7 +508,7 @@ internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCo { if (XmlReaderHelper.IsStartElement(reader, "bookViews", _ns)) { - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; while (!reader.EOF) @@ -523,7 +523,7 @@ internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCo reader.Skip(); } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -531,7 +531,7 @@ internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCo } else if (XmlReaderHelper.IsStartElement(reader, "sheets", _ns)) { - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; var sheetCount = 0; @@ -549,13 +549,13 @@ internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCo sheetCount++; reader.Skip(); } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { yield break; } @@ -564,7 +564,7 @@ internal static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCo } [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal async Task> GetWorkbookRelsAsync(ReadOnlyCollection entries, CancellationToken ct = default) + internal async Task> GetWorkbookRelsAsync(ReadOnlyCollection entries, CancellationToken cancellationToken = default) { var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY @@ -575,7 +575,7 @@ internal async Task> GetWorkbookRelsAsync(ReadOnlyCollection(); - await foreach (var sheetRecord in ReadWorkbookAsync(entries, ct).WithCancellation(ct).ConfigureAwait(false)) + await foreach (var sheetRecord in ReadWorkbookAsync(entries, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) { sheetRecords.Add(sheetRecord); } @@ -586,7 +586,7 @@ internal async Task> GetWorkbookRelsAsync(ReadOnlyCollection> GetWorkbookRelsAsync(ReadOnlyCollection ReadCellAndSetColumnIndexAsync(XmlReader reader, int columnIndex, bool withoutCR, int startColumnIndex, string aR, string aT, CancellationToken ct = default) + private async Task ReadCellAndSetColumnIndexAsync(XmlReader reader, int columnIndex, bool withoutCR, int startColumnIndex, string aR, string aT, CancellationToken cancellationToken = default) { const int xfIndex = -1; int newColumnIndex; @@ -650,17 +650,17 @@ private async Task ReadCellAndSetColumnIndexAsync(XmlReader reade if (columnIndex < startColumnIndex) { - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) return new CellAndColumn(null, columnIndex); while (!reader.EOF) - if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; return new CellAndColumn(null, columnIndex); } - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) return new CellAndColumn(null, columnIndex); object value = null; @@ -678,7 +678,7 @@ private async Task ReadCellAndSetColumnIndexAsync(XmlReader reade if (!string.IsNullOrEmpty(rawValue)) ConvertCellValue(rawValue, aT, xfIndex, out value); } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -769,7 +769,7 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec } [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal async Task> GetDimensionsAsync(CancellationToken ct = default) + internal async Task> GetDimensionsAsync(CancellationToken cancellationToken = default) { var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY @@ -849,14 +849,14 @@ internal async Task> GetDimensionsAsync(CancellationToken ct = if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) throw new InvalidDataException("No worksheet data found for the sheet"); - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) throw new InvalidOperationException("Excel sheet does not contain any data"); while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; while (!reader.EOF) @@ -865,7 +865,7 @@ internal async Task> GetDimensionsAsync(CancellationToken ct = { maxRowIndex++; - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; var cellIndex = -1; @@ -877,17 +877,17 @@ internal async Task> GetDimensionsAsync(CancellationToken ct = maxColumnIndex = Math.Max(maxColumnIndex, cellIndex); } - if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; } } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -929,7 +929,7 @@ public GetMaxRowColumnIndexResult(bool isSuccess, bool withoutCR, int maxRowInde } [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal static async Task TryGetMaxRowColumnIndexAsync(ZipArchiveEntry sheetEntry, CancellationToken ct = default) + internal static async Task TryGetMaxRowColumnIndexAsync(ZipArchiveEntry sheetEntry, CancellationToken cancellationToken = default) { var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY @@ -947,7 +947,7 @@ internal static async Task TryGetMaxRowColumnIndexAs { while (await reader.ReadAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false)) { @@ -998,14 +998,14 @@ internal static async Task TryGetMaxRowColumnIndexAs if (!XmlReaderHelper.IsStartElement(reader, "worksheet", _ns)) return new GetMaxRowColumnIndexResult(false); - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) return new GetMaxRowColumnIndexResult(false); while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; while (!reader.EOF) @@ -1014,7 +1014,7 @@ internal static async Task TryGetMaxRowColumnIndexAs { maxRowIndex++; - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; // Cells @@ -1027,17 +1027,17 @@ internal static async Task TryGetMaxRowColumnIndexAs maxColumnIndex = Math.Max(maxColumnIndex, cellIndex); } - if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; } } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -1066,7 +1066,7 @@ public MergeCellsResult(bool isSuccess, MergeCells mergeCells) } [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal static async Task TryGetMergeCellsAsync(ZipArchiveEntry sheetEntry, CancellationToken ct = default) + internal static async Task TryGetMergeCellsAsync(ZipArchiveEntry sheetEntry, CancellationToken cancellationToken = default) { var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY @@ -1088,7 +1088,7 @@ internal static async Task TryGetMergeCellsAsync(ZipArchiveEnt continue; } - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) return new MergeCellsResult(false); while (!reader.EOF) @@ -1117,9 +1117,9 @@ internal static async Task TryGetMergeCellsAsync(ZipArchiveEnt } } - await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false); + await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false); } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index bb929499..b2b38dd3 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -56,7 +56,7 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke cancellationToken.ThrowIfCancellationRequested(); - var reader = await ExcelOpenXmlSheetReader.CreateAsync(_stream, _configuration, ct: cancellationToken).ConfigureAwait(false); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(_stream, _configuration, cancellationToken: cancellationToken).ConfigureAwait(false); var sheetRecords = (await reader.GetWorkbookRelsAsync(_archive.Entries, cancellationToken).ConfigureAwait(false)).ToArray(); foreach (var sheetRecord in sheetRecords.OrderBy(o => o.Id)) { diff --git a/src/MiniExcel/Picture/MiniExcelPictureImplement.cs b/src/MiniExcel/Picture/MiniExcelPictureImplement.cs index 73ecb3d7..34a296ba 100644 --- a/src/MiniExcel/Picture/MiniExcelPictureImplement.cs +++ b/src/MiniExcel/Picture/MiniExcelPictureImplement.cs @@ -13,12 +13,12 @@ namespace MiniExcelLibs.Picture internal static partial class MiniExcelPictureImplement { [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task AddPictureAsync(Stream excelStream, CancellationToken ct = default, params MiniExcelPicture[] images) + public static async Task AddPictureAsync(Stream excelStream, CancellationToken cancellationToken = default, params MiniExcelPicture[] images) { // get sheets var excelArchive = new ExcelOpenXmlZip(excelStream); - var reader = await ExcelOpenXmlSheetReader.CreateAsync(excelStream, null, ct: ct).ConfigureAwait(false); - var sheetEntries = await reader.GetWorkbookRelsAsync(excelArchive.entries, ct).ConfigureAwait(false); + var reader = await ExcelOpenXmlSheetReader.CreateAsync(excelStream, null, cancellationToken: cancellationToken).ConfigureAwait(false); + var sheetEntries = await reader.GetWorkbookRelsAsync(excelArchive.entries, cancellationToken).ConfigureAwait(false); var drawingRelId = $"rId{Guid.NewGuid():N}"; var drawingId = Guid.NewGuid().ToString("N"); diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs index dd884cce..e0bd84d2 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs @@ -149,7 +149,7 @@ internal partial class ExcelOpenXmlTemplate #endif [Zomp.SyncMethodGenerator.CreateSyncVersion] - private async Task GenerateSheetXmlImplByUpdateModeAsync(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, IDictionary inputMaps, IDictionary sharedStrings, bool mergeCells = false, CancellationToken ct = default) + private async Task GenerateSheetXmlImplByUpdateModeAsync(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, IDictionary inputMaps, IDictionary sharedStrings, bool mergeCells = false, CancellationToken cancellationToken = default) { var doc = new XmlDocument(); doc.Load(sheetStream); @@ -166,7 +166,7 @@ private async Task GenerateSheetXmlImplByUpdateModeAsync(ZipArchiveEntry sheetZi GetMergeCells(doc, worksheet); UpdateDimensionAndGetRowsInfo(inputMaps, doc, rows, !mergeCells); - await WriteSheetXmlAsync(stream, doc, sheetData, mergeCells, ct).ConfigureAwait(false); + await WriteSheetXmlAsync(stream, doc, sheetData, mergeCells, cancellationToken).ConfigureAwait(false); } @@ -298,7 +298,7 @@ private class ConditionalFormatRange } [Zomp.SyncMethodGenerator.CreateSyncVersion] - private async Task WriteSheetXmlAsync(Stream outputFileStream, XmlDocument doc, XmlNode sheetData, bool mergeCells = false, CancellationToken ct = default) + private async Task WriteSheetXmlAsync(Stream outputFileStream, XmlDocument doc, XmlNode sheetData, bool mergeCells = false, CancellationToken cancellationToken = default) { //Q.Why so complex? //A.Because try to use string stream avoid OOM when rendering rows @@ -334,12 +334,12 @@ private async Task WriteSheetXmlAsync(Stream outputFileStream, XmlDocument doc, { await writer.WriteAsync(contents[0] #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); await writer.WriteAsync($"<{prefix}sheetData>" #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); // prefix problem @@ -476,7 +476,7 @@ await writer.WriteAsync($"<{prefix}sheetData>" rowIndexDiff = rowIndexDiff, }; - generateCellValuesContext = await GenerateCellValuesAsync(generateCellValuesContext, endPrefix, writer, rowXml, mergeRowCount, isHeaderRow, rowInfo, row, groupingRowDiff, innerXml, outerXmlOpen, row, ct).ConfigureAwait(false); + generateCellValuesContext = await GenerateCellValuesAsync(generateCellValuesContext, endPrefix, writer, rowXml, mergeRowCount, isHeaderRow, rowInfo, row, groupingRowDiff, innerXml, outerXmlOpen, row, cancellationToken).ConfigureAwait(false); rowIndexDiff = generateCellValuesContext.rowIndexDiff; headerDiff = generateCellValuesContext.headerDiff; @@ -546,7 +546,7 @@ await writer.WriteAsync($"<{prefix}sheetData>" await writer.WriteAsync($"" #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); @@ -554,20 +554,20 @@ await writer.WriteAsync($"" { await writer.WriteAsync($"<{prefix}mergeCells count=\"{_newXMergeCellInfos.Count}\">" #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); foreach (var cell in _newXMergeCellInfos) { await writer.WriteAsync(cell.ToXmlString(prefix) #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); } await writer.WriteLineAsync($"" #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); } @@ -576,7 +576,7 @@ await writer.WriteLineAsync($"" { await writer.WriteAsync(phoneticPrXml #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); } @@ -585,14 +585,14 @@ await writer.WriteAsync(phoneticPrXml { await writer.WriteAsync(string.Join(string.Empty, newConditionalFormatRanges.Select(cf => cf.Node.OuterXml)) #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); } await writer.WriteAsync(contents[1] #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); } @@ -614,7 +614,7 @@ class GenerateCellValuesContext private async Task GenerateCellValuesAsync(GenerateCellValuesContext generateCellValuesContext, string endPrefix, StreamWriter writer, StringBuilder rowXml, int mergeRowCount, bool isHeaderRow, XRowInfo rowInfo, XmlElement row, int groupingRowDiff, - string innerXml, StringBuilder outerXmlOpen, XmlElement rowElement, CancellationToken ct = default) + string innerXml, StringBuilder outerXmlOpen, XmlElement rowElement, CancellationToken cancellationToken = default) { var rowIndexDiff = generateCellValuesContext.rowIndexDiff; var headerDiff = generateCellValuesContext.headerDiff; @@ -830,7 +830,7 @@ private async Task GenerateCellValuesAsync(GenerateCe ProcessFormulas(rowXml, newRowIndex); await writer.WriteAsync(rowXml.ToString() #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); @@ -879,7 +879,7 @@ await writer.WriteAsync(rowXml.ToString() newRow.InnerXml = new StringBuilder(newRow.InnerXml).Replace("{{$rowindex}}", mergeBaseRowIndex.ToString()).ToString(); await writer.WriteAsync(CleanXml(newRow.OuterXml, endPrefix) #if NET7_0_OR_GREATER - .AsMemory(), ct + .AsMemory(), cancellationToken #endif ).ConfigureAwait(false); } diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs index 63763c2c..fdf5bd8e 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.MergeCells.cs @@ -15,29 +15,29 @@ namespace MiniExcelLibs.OpenXml.SaveByTemplate internal partial class ExcelOpenXmlTemplate { [Zomp.SyncMethodGenerator.CreateSyncVersion] - public async Task MergeSameCellsAsync(string path, CancellationToken ct = default) + public async Task MergeSameCellsAsync(string path, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - await MergeSameCellsImplAsync(stream, ct).ConfigureAwait(false); + await MergeSameCellsImplAsync(stream, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public async Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken ct = default) + public async Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken cancellationToken = default) { using (Stream stream = new MemoryStream(fileInBytes)) - await MergeSameCellsImplAsync(stream, ct).ConfigureAwait(false); + await MergeSameCellsImplAsync(stream, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - private async Task MergeSameCellsImplAsync(Stream stream, CancellationToken ct = default) + private async Task MergeSameCellsImplAsync(Stream stream, CancellationToken cancellationToken = default) { await stream.CopyToAsync(_outputFileStream #if NETCOREAPP2_1_OR_GREATER - , ct + , cancellationToken #endif ).ConfigureAwait(false); - var reader = await ExcelOpenXmlSheetReader.CreateAsync (_outputFileStream, null, ct: ct).ConfigureAwait(false); + var reader = await ExcelOpenXmlSheetReader.CreateAsync (_outputFileStream, null, cancellationToken: cancellationToken).ConfigureAwait(false); var archive = new ExcelOpenXmlZip(_outputFileStream, mode: ZipArchiveMode.Update, true, Encoding.UTF8); //read sharedString @@ -61,7 +61,7 @@ await stream.CopyToAsync(_outputFileStream var entry = archive.zipFile.CreateEntry(fullName); using (var zipStream = entry.Open()) { - await GenerateSheetXmlImplByUpdateModeAsync(sheet, zipStream, sheetStream, new Dictionary(), sharedStrings, mergeCells: true, ct).ConfigureAwait(false); + await GenerateSheetXmlImplByUpdateModeAsync(sheet, zipStream, sheetStream, new Dictionary(), sharedStrings, mergeCells: true, cancellationToken).ConfigureAwait(false); //doc.Save(zipStream); //don't do it beacause: https://user-images.githubusercontent.com/12729184/114361127-61a5d100-9ba8-11eb-9bb9-34f076ee28a2.png } } diff --git a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs index 4c7c66f2..6b5a9455 100644 --- a/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs +++ b/src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs @@ -44,28 +44,28 @@ public ExcelOpenXmlTemplate(Stream stream, IConfiguration configuration, InputVa } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public async Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken ct = default) + public async Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(templatePath)) - await SaveAsByTemplateImplAsync(stream, value, ct).ConfigureAwait(false); + await SaveAsByTemplateImplAsync(stream, value, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public async Task SaveAsByTemplateAsync(byte[] templateBytes, object value, CancellationToken ct = default) + public async Task SaveAsByTemplateAsync(byte[] templateBytes, object value, CancellationToken cancellationToken = default) { using (Stream stream = new MemoryStream(templateBytes)) - await SaveAsByTemplateImplAsync(stream, value, ct).ConfigureAwait(false); + await SaveAsByTemplateImplAsync(stream, value, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] - internal async Task SaveAsByTemplateImplAsync(Stream templateStream, object value, CancellationToken ct = default) + internal async Task SaveAsByTemplateImplAsync(Stream templateStream, object value, CancellationToken cancellationToken = default) { //only support xlsx //templateStream.CopyTo(_outputFileStream); // foreach all templateStream and create file for _outputFileStream and not create sheet file templateStream.Position = 0; - var templateReader = await ExcelOpenXmlSheetReader.CreateAsync(templateStream, null, ct: ct).ConfigureAwait(false); + var templateReader = await ExcelOpenXmlSheetReader.CreateAsync(templateStream, null, cancellationToken: cancellationToken).ConfigureAwait(false); var outputFileArchive = new ExcelOpenXmlZip(_outputFileStream, mode: ZipArchiveMode.Create, true, Encoding.UTF8, isUpdateMode: false); try { @@ -106,7 +106,7 @@ internal async Task SaveAsByTemplateImplAsync(Stream templateStream, object valu { await originalEntryStream.CopyToAsync(newEntryStream #if NETCOREAPP2_1_OR_GREATER - , ct + , cancellationToken #endif ).ConfigureAwait(false); } @@ -155,7 +155,7 @@ await originalEntryStream.CopyToAsync(newEntryStream var calcChainEntry = outputFileArchive.zipFile.CreateEntry(calcChainPathName); using (var calcChainStream = calcChainEntry.Open()) { - await CalcChainHelper.GenerateCalcChainSheetAsync(calcChainStream, _calcChainContent.ToString(), ct).ConfigureAwait(false); + await CalcChainHelper.GenerateCalcChainSheetAsync(calcChainStream, _calcChainContent.ToString(), cancellationToken).ConfigureAwait(false); } } else @@ -172,7 +172,7 @@ await originalEntryStream.CopyToAsync(newEntryStream { await originalEntryStream.CopyToAsync(newEntryStream #if NETCOREAPP2_1_OR_GREATER - , ct + , cancellationToken #endif ).ConfigureAwait(false); } diff --git a/src/MiniExcel/Utils/StringHelper.cs b/src/MiniExcel/Utils/StringHelper.cs index 067f5a5d..889a8e32 100644 --- a/src/MiniExcel/Utils/StringHelper.cs +++ b/src/MiniExcel/Utils/StringHelper.cs @@ -19,10 +19,10 @@ internal static partial class StringHelper /// Copied and modified from ExcelDataReader - @MIT License /// [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task ReadStringItemAsync(XmlReader reader, CancellationToken ct = default) + public static async Task ReadStringItemAsync(XmlReader reader, CancellationToken cancellationToken = default) { var result = new StringBuilder(); - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) return string.Empty; while (!reader.EOF) @@ -32,15 +32,15 @@ public static async Task ReadStringItemAsync(XmlReader reader, Cancellat // There are multiple in a . Concatenate within an . result.Append(await reader.ReadElementContentAsStringAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false)); } else if (XmlReaderHelper.IsStartElement(reader, "r", _ns)) { - result.Append(await ReadRichTextRunAsync(reader, ct)); + result.Append(await ReadRichTextRunAsync(reader, cancellationToken).ConfigureAwait(false)); } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -53,10 +53,10 @@ public static async Task ReadStringItemAsync(XmlReader reader, Cancellat /// Copied and modified from ExcelDataReader - @MIT License /// [Zomp.SyncMethodGenerator.CreateSyncVersion] - private static async Task ReadRichTextRunAsync(XmlReader reader, CancellationToken ct = default) + private static async Task ReadRichTextRunAsync(XmlReader reader, CancellationToken cancellationToken = default) { var result = new StringBuilder(); - if (!await XmlReaderHelper.ReadFirstContentAsync(reader, ct)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) return string.Empty; while (!reader.EOF) @@ -65,11 +65,11 @@ private static async Task ReadRichTextRunAsync(XmlReader reader, Cancell { result.Append(await reader.ReadElementContentAsStringAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false)); } - else if (!await XmlReaderHelper.SkipContentAsync(reader, ct)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } diff --git a/src/MiniExcel/Utils/XmlReaderHelper.cs b/src/MiniExcel/Utils/XmlReaderHelper.cs index 2d8cbf23..2fbe3cd8 100644 --- a/src/MiniExcel/Utils/XmlReaderHelper.cs +++ b/src/MiniExcel/Utils/XmlReaderHelper.cs @@ -15,16 +15,16 @@ internal static partial class XmlReaderHelper /// /// [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task PassXmlDeclarationAndWorksheetAsync(this XmlReader reader, CancellationToken ct = default) + public static async Task PassXmlDeclarationAndWorksheetAsync(this XmlReader reader, CancellationToken cancellationToken = default) { await reader.MoveToContentAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); await reader.ReadAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); } @@ -34,24 +34,24 @@ await reader.ReadAsync() /// /// [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SkipToNextSameLevelDomAsync(XmlReader reader, CancellationToken ct = default) + public static async Task SkipToNextSameLevelDomAsync(XmlReader reader, CancellationToken cancellationToken = default) { while (!reader.EOF) { - if (!await SkipContentAsync(reader, ct)) + if (!await SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; } } //Method from ExcelDataReader @MIT License [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task ReadFirstContentAsync(XmlReader reader, CancellationToken ct = default) + public static async Task ReadFirstContentAsync(XmlReader reader, CancellationToken cancellationToken = default) { if (reader.IsEmptyElement) { await reader.ReadAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); return false; @@ -59,12 +59,12 @@ await reader.ReadAsync() await reader.MoveToContentAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); await reader.ReadAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); return true; @@ -72,13 +72,13 @@ await reader.ReadAsync() //Method from ExcelDataReader @MIT License [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task SkipContentAsync(XmlReader reader, CancellationToken ct = default) + public static async Task SkipContentAsync(XmlReader reader, CancellationToken cancellationToken = default) { if (reader.NodeType == XmlNodeType.EndElement) { await reader.ReadAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); return false; @@ -86,7 +86,7 @@ await reader.ReadAsync() await reader.SkipAsync() #if NET6_0_OR_GREATER - .WaitAsync(ct) + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); return true; @@ -105,7 +105,7 @@ public static string GetAttribute(XmlReader reader, string name, params string[] } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream, [EnumeratorCancellation]CancellationToken ct = default, params string[] nss) + public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream, [EnumeratorCancellation]CancellationToken cancellationToken = default, params string[] nss) { var xmlSettings = GetXmlReaderSettings( #if SYNC_ONLY @@ -119,17 +119,17 @@ public static async IAsyncEnumerable GetSharedStringsAsync(Stream stream if (!IsStartElement(reader, "sst", nss)) yield break; - if (!await ReadFirstContentAsync(reader, ct).ConfigureAwait(false)) + if (!await ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) yield break; while (!reader.EOF) { if (IsStartElement(reader, "si", nss)) { - var value = await StringHelper.ReadStringItemAsync(reader, ct).ConfigureAwait(false); + var value = await StringHelper.ReadStringItemAsync(reader, cancellationToken).ConfigureAwait(false); yield return value; } - else if (!await SkipContentAsync(reader, ct).ConfigureAwait(false)) + else if (!await SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } diff --git a/src/MiniExcel/Utils/calChainHelper.cs b/src/MiniExcel/Utils/calChainHelper.cs index cd804c3f..c94c1886 100644 --- a/src/MiniExcel/Utils/calChainHelper.cs +++ b/src/MiniExcel/Utils/calChainHelper.cs @@ -27,7 +27,7 @@ public static string GetCalcChainContent( List cellRefs, int sheetIndex } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task GenerateCalcChainSheetAsync(Stream calcChainStream, string calcChainContent, CancellationToken ct = default) + public static async Task GenerateCalcChainSheetAsync(Stream calcChainStream, string calcChainContent, CancellationToken cancellationToken = default) { using (var writer = new StreamWriter(calcChainStream, Encoding.UTF8)) { diff --git a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs index 218c6241..b7382576 100644 --- a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs @@ -1235,7 +1235,7 @@ await Assert.ThrowsAsync(async () => cts.CancelAsync(); await using var stream = FileHelper.OpenRead(path); - var rows = stream.QueryAsync(ct: cts.Token).ToBlockingEnumerable(cts.Token).ToList(); + var rows = stream.QueryAsync(cancellationToken: cts.Token).ToBlockingEnumerable(cts.Token).ToList(); }); } @@ -1255,7 +1255,7 @@ await Assert.ThrowsAsync(async () => }); await using var stream = FileHelper.OpenRead(path); - var d = stream.QueryAsync(ct: cts.Token).ToBlockingEnumerable(cts.Token); + var d = stream.QueryAsync(cancellationToken: cts.Token).ToBlockingEnumerable(cts.Token); await cancelTask; _ = d.ToList(); }); diff --git a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs index 62293a0c..cf7a3972 100644 --- a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs +++ b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs @@ -898,7 +898,7 @@ await Assert.ThrowsAsync(async () => }; await cts.CancelAsync(); - await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value, ct: cts.Token); + await MiniExcel.SaveAsByTemplateAsync(path.ToString(), templatePath, value, cancellationToken: cts.Token); }); } } \ No newline at end of file From 9b3993d3f6ef82824be11d90e9d37583528a6fc1 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 13:10:04 -0400 Subject: [PATCH 19/25] Remove async code from generated sync code --- src/MiniExcel/MiniExcel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index b0b63fdf..e90b85be 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -359,7 +359,7 @@ public static async Task> GetSheetDimensionsAsync(string path, public static async Task> GetSheetDimensionsAsync(this Stream stream, CancellationToken cancellationToken = default) { var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, null, cancellationToken: cancellationToken).ConfigureAwait(false); - return reader.GetDimensions(); + return await reader.GetDimensionsAsync(cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -390,7 +390,7 @@ public static async Task ConvertXlsxToCsvAsync(string xlsx, string csv, Cancella [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async Task ConvertXlsxToCsvAsync(Stream xlsx, Stream csv, CancellationToken cancellationToken = default) { - var value = Query(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX); + var value = QueryAsync(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX); await SaveAsAsync(csv, value, printHeader: false, excelType: ExcelType.CSV, cancellationToken: cancellationToken).ConfigureAwait(false); } } From dd630fea4ac517ce3341d4bd6b800e72454cf2bf Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 15:02:56 -0400 Subject: [PATCH 20/25] Pass all tests and clean up --- src/MiniExcel/Csv/CsvReader.cs | 2 + src/MiniExcel/MiniExcel.cs | 2 + .../OpenXml/ExcelOpenXmlSheetReader.cs | 18 ++ .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 198 ++++++++++-------- .../OpenXml/MiniExcelAsyncStreamWriter.cs | 10 +- src/MiniExcel/Utils/calChainHelper.cs | 9 +- .../MiniExcelOpenXmlAsyncTests.cs | 4 +- .../MiniExcelTemplateAsyncTests.cs | 2 +- 8 files changed, 143 insertions(+), 102 deletions(-) diff --git a/src/MiniExcel/Csv/CsvReader.cs b/src/MiniExcel/Csv/CsvReader.cs index 07ef95ea..dddec16d 100644 --- a/src/MiniExcel/Csv/CsvReader.cs +++ b/src/MiniExcel/Csv/CsvReader.cs @@ -26,6 +26,8 @@ public CsvReader(Stream stream, IConfiguration configuration) [Zomp.SyncMethodGenerator.CreateSyncVersion] public async IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, [EnumeratorCancellation] CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (startCell != "A1") throw new NotImplementedException("CSV does not implement parameter startCell"); diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index e90b85be..35ffd4e1 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -249,6 +249,8 @@ public async static Task QueryAsDataTableAsync(string path, bool useH [Zomp.SyncMethodGenerator.CreateSyncVersion] public async static Task QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/ sheetName = (await stream.GetSheetNamesAsync(configuration as OpenXmlConfiguration, cancellationToken).ConfigureAwait(false)).First(); diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs index f74e9050..894516ae 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs @@ -61,6 +61,8 @@ public IAsyncEnumerable> QueryAsync(bool useHeaderRo [Zomp.SyncMethodGenerator.CreateSyncVersion] public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (!ReferenceHelper.ParseReference(startCell, out var startColumnIndex, out var startRowIndex)) { throw new InvalidDataException($"Value {startCell} is not a valid cell reference."); @@ -96,6 +98,8 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea [Zomp.SyncMethodGenerator.CreateSyncVersion] public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (startRowIndex <= 0) { throw new ArgumentOutOfRangeException(nameof(startRowIndex), "Start row index is 1-based and must be greater than 0."); @@ -140,6 +144,8 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async IAsyncEnumerable> InternalQueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, [EnumeratorCancellation] CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false @@ -317,6 +323,8 @@ internal async IAsyncEnumerable> InternalQueryRangeA [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async IAsyncEnumerable QueryImplAsync(IAsyncEnumerable> values, string startCell, bool hasHeader, Configuration configuration, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new() { + cancellationToken.ThrowIfCancellationRequested(); + var type = typeof(T); //TODO:need to optimize @@ -449,6 +457,8 @@ private static void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task SetSharedStringsAsync(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (_sharedStrings != null) return; var sharedStringsEntry = _archive.GetEntry("xl/sharedStrings.xml"); @@ -634,6 +644,8 @@ public CellAndColumn(object cellValue, int columnIndex) [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task ReadCellAndSetColumnIndexAsync(XmlReader reader, int columnIndex, bool withoutCR, int startColumnIndex, string aR, string aT, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const int xfIndex = -1; int newColumnIndex; @@ -771,6 +783,8 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async Task> GetDimensionsAsync(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false @@ -931,6 +945,8 @@ public GetMaxRowColumnIndexResult(bool isSuccess, bool withoutCR, int maxRowInde [Zomp.SyncMethodGenerator.CreateSyncVersion] internal static async Task TryGetMaxRowColumnIndexAsync(ZipArchiveEntry sheetEntry, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false @@ -1068,6 +1084,8 @@ public MergeCellsResult(bool isSuccess, MergeCells mergeCells) [Zomp.SyncMethodGenerator.CreateSyncVersion] internal static async Task TryGetMergeCellsAsync(ZipArchiveEntry sheetEntry, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( #if SYNC_ONLY false diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index b2b38dd3..bcd5a3bd 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -22,6 +22,8 @@ public async Task SaveAsAsync(CancellationToken cancellationToken = defau { try { + cancellationToken.ThrowIfCancellationRequested(); + await GenerateDefaultOpenXmlAsync(cancellationToken).ConfigureAwait(false); var sheets = GetSheets(); @@ -30,7 +32,7 @@ public async Task SaveAsAsync(CancellationToken cancellationToken = defau foreach (var sheet in sheets) { cancellationToken.ThrowIfCancellationRequested(); - + _sheets.Add(sheet.Item1); //TODO:remove _currentSheetIndex = sheet.Item1.SheetIdx; var rows = await CreateSheetXmlAsync(sheet.Item2, sheet.Item1.Path, cancellationToken).ConfigureAwait(false); @@ -51,6 +53,8 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke { try { + cancellationToken.ThrowIfCancellationRequested(); + if (!_configuration.FastMode) throw new InvalidOperationException("Insert requires fast mode to be enabled"); @@ -67,7 +71,7 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke if (existSheetDto != null && !overwriteSheet) throw new Exception($"Sheet “{_defaultSheetName}” already exist"); - await GenerateStylesXmlAsync(cancellationToken);//GenerateStylesXml必须在校验overwriteSheet之后,避免不必要的样式更改 + await GenerateStylesXmlAsync(cancellationToken).ConfigureAwait(false);//GenerateStylesXml必须在校验overwriteSheet之后,避免不必要的样式更改 int rowsWritten; if (existSheetDto == null) @@ -76,36 +80,36 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke var insertSheetInfo = GetSheetInfos(_defaultSheetName); var insertSheetDto = insertSheetInfo.ToDto(_currentSheetIndex); _sheets.Add(insertSheetDto); - rowsWritten = await CreateSheetXmlAsync(_value, insertSheetDto.Path, cancellationToken); + rowsWritten = await CreateSheetXmlAsync(_value, insertSheetDto.Path, cancellationToken).ConfigureAwait(false); } else { _currentSheetIndex = existSheetDto.SheetIdx; _archive.Entries.Single(s => s.FullName == existSheetDto.Path).Delete(); - rowsWritten = await CreateSheetXmlAsync(_value, existSheetDto.Path, cancellationToken); + rowsWritten = await CreateSheetXmlAsync(_value, existSheetDto.Path, cancellationToken).ConfigureAwait(false); } - await AddFilesToZipAsync(cancellationToken); + await AddFilesToZipAsync(cancellationToken).ConfigureAwait(false); _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(_currentSheetIndex - 1))?.Delete(); - await GenerateDrawinRelXmlAsync(_currentSheetIndex - 1, cancellationToken); + await GenerateDrawinRelXmlAsync(_currentSheetIndex - 1, cancellationToken).ConfigureAwait(false); _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(_currentSheetIndex - 1))?.Delete(); - await GenerateDrawingXmlAsync(_currentSheetIndex - 1, cancellationToken); + await GenerateDrawingXmlAsync(_currentSheetIndex - 1, cancellationToken).ConfigureAwait(false); GenerateWorkBookXmls(out StringBuilder workbookXml, out StringBuilder workbookRelsXml, out Dictionary sheetsRelsXml); foreach (var sheetRelsXml in sheetsRelsXml) { var sheetRelsXmlPath = ExcelFileNames.SheetRels(sheetRelsXml.Key); _archive.Entries.SingleOrDefault(s => s.FullName == sheetRelsXmlPath)?.Delete(); - await CreateZipEntryAsync(sheetRelsXmlPath, null, ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value), cancellationToken); + await CreateZipEntryAsync(sheetRelsXmlPath, null, ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value), cancellationToken).ConfigureAwait(false); } _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Workbook)?.Delete(); - await CreateZipEntryAsync(ExcelFileNames.Workbook, ExcelContentTypes.Workbook, ExcelXml.DefaultWorkbookXml.Replace("{{sheets}}", workbookXml.ToString()), cancellationToken); + await CreateZipEntryAsync(ExcelFileNames.Workbook, ExcelContentTypes.Workbook, ExcelXml.DefaultWorkbookXml.Replace("{{sheets}}", workbookXml.ToString()), cancellationToken).ConfigureAwait(false); _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels)?.Delete(); - await CreateZipEntryAsync(ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()), cancellationToken); + await CreateZipEntryAsync(ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()), cancellationToken).ConfigureAwait(false); await InsertContentTypesXmlAsync(cancellationToken); @@ -120,28 +124,28 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke [Zomp.SyncMethodGenerator.CreateSyncVersion] internal async Task GenerateDefaultOpenXmlAsync(CancellationToken cancellationToken) { - await CreateZipEntryAsync(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels, cancellationToken); - await CreateZipEntryAsync(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString, cancellationToken); - await GenerateStylesXmlAsync(cancellationToken); + await CreateZipEntryAsync(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels, cancellationToken).ConfigureAwait(false); + await CreateZipEntryAsync(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString, cancellationToken).ConfigureAwait(false); + await GenerateStylesXmlAsync(cancellationToken).ConfigureAwait(false); } private async Task CreateSheetXmlAsync(object values, string sheetPath, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + var entry = _archive.CreateEntry(sheetPath, CompressionLevel.Fastest); var rowsWritten = 0; - + using (var zipStream = entry.Open()) using (var writer = new MiniExcelAsyncStreamWriter(zipStream, _utf8WithBom, _configuration.BufferSize, cancellationToken)) { if (values == null) { - await WriteEmptySheetAsync(writer); + await WriteEmptySheetAsync(writer).ConfigureAwait(false); } else { - rowsWritten = await WriteValuesAsync(writer, values, cancellationToken); + rowsWritten = await WriteValuesAsync(writer, values, cancellationToken).ConfigureAwait(false); } } _zipDictionary.Add(sheetPath, new ZipPackageInfo(entry, ExcelContentTypes.Worksheet)); @@ -150,7 +154,7 @@ private async Task CreateSheetXmlAsync(object values, string sheetPath, Can private static async Task WriteEmptySheetAsync(MiniExcelAsyncStreamWriter writer) { - await writer.WriteAsync(ExcelXml.EmptySheetXml); + await writer.WriteAsync(ExcelXml.EmptySheetXml).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -162,7 +166,7 @@ MiniExcelAsyncStreamWriter writer #endif ) { - var dimensionPlaceholderPostition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension); + var dimensionPlaceholderPostition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension).ConfigureAwait(false); await writer.WriteAsync(WorksheetXml.DimensionPlaceholder); // end of code will be replaced return dimensionPlaceholderPostition; @@ -178,10 +182,10 @@ private static async Task WriteDimensionAsync( int maxRowIndex, int maxColumnIndex, long placeholderPosition) { // Flush and save position so that we can get back again. - var position = await writer.FlushAsync(); + var position = await writer.FlushAsync().ConfigureAwait(false); writer.SetPosition(placeholderPosition); - await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}"""); + await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""").ConfigureAwait(false); writer.SetPosition(position); } @@ -196,7 +200,7 @@ private async Task WriteValuesAsync( object values, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + IMiniExcelWriteAdapter writeAdapter = null; if (!MiniExcelWriteAdapterFactory.TryGetAsyncWriteAdapter(values, _configuration, out var asyncWriteAdapter)) { @@ -209,17 +213,17 @@ private async Task WriteValuesAsync( #if SYNC_ONLY props = writeAdapter?.GetColumns(); #else - props = writeAdapter != null ? writeAdapter?.GetColumns() : await asyncWriteAdapter.GetColumnsAsync(); + props = writeAdapter != null ? writeAdapter?.GetColumns() : await asyncWriteAdapter.GetColumnsAsync().ConfigureAwait(false); #endif if (props == null) { - await WriteEmptySheetAsync(writer); + await WriteEmptySheetAsync(writer).ConfigureAwait(false); return 0; } int maxRowIndex; var maxColumnIndex = props.Count(x => x != null && !x.ExcelIgnore); - await writer.WriteAsync(WorksheetXml.StartWorksheetWithRelationship); + await writer.WriteAsync(WorksheetXml.StartWorksheetWithRelationship).ConfigureAwait(false); long dimensionPlaceholderPostition = 0; @@ -227,22 +231,22 @@ private async Task WriteValuesAsync( if (isKnownCount) { maxRowIndex = _printHeader ? count + 1 : count; - await writer.WriteAsync(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, props.Count))); + await writer.WriteAsync(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, props.Count))).ConfigureAwait(false); } else if (_configuration.FastMode) { - dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer); + dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer).ConfigureAwait(false); } //sheet view - await writer.WriteAsync(GetSheetViews()); + await writer.WriteAsync(GetSheetViews()).ConfigureAwait(false); //cols:width ExcelWidthCollection widths = null; long columnWidthsPlaceholderPosition = 0; if (_configuration.EnableAutoWidth) { - columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, maxColumnIndex); + columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, maxColumnIndex, cancellationToken).ConfigureAwait(false); widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props); } else @@ -251,11 +255,11 @@ private async Task WriteValuesAsync( } //header - await writer.WriteAsync(WorksheetXml.StartSheetData); + await writer.WriteAsync(WorksheetXml.StartSheetData).ConfigureAwait(false); var currentRowIndex = 0; if (_printHeader) { - await PrintHeaderAsync(writer, props, cancellationToken); + await PrintHeaderAsync(writer, props, cancellationToken).ConfigureAwait(false); currentRowIndex++; } @@ -264,14 +268,14 @@ private async Task WriteValuesAsync( foreach (var row in writeAdapter.GetRows(props, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - - await writer.WriteAsync(WorksheetXml.StartRow(++currentRowIndex)); + + await writer.WriteAsync(WorksheetXml.StartRow(++currentRowIndex)).ConfigureAwait(false); foreach (var cellValue in row) { cancellationToken.ThrowIfCancellationRequested(); await WriteCellAsync(writer, currentRowIndex, cellValue.CellIndex, cellValue.Value, cellValue.Prop, widths); } - await writer.WriteAsync(WorksheetXml.EndRow); + await writer.WriteAsync(WorksheetXml.EndRow).ConfigureAwait(false); } } else @@ -280,36 +284,36 @@ private async Task WriteValuesAsync( await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - await writer.WriteAsync(WorksheetXml.StartRow(++currentRowIndex)); + await writer.WriteAsync(WorksheetXml.StartRow(++currentRowIndex)).ConfigureAwait(false); - await foreach (var cellValue in row) + await foreach (var cellValue in row.WithCancellation(cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); - await WriteCellAsync(writer, currentRowIndex, cellValue.CellIndex, cellValue.Value, cellValue.Prop, widths); + await WriteCellAsync(writer, currentRowIndex, cellValue.CellIndex, cellValue.Value, cellValue.Prop, widths).ConfigureAwait(false); } - await writer.WriteAsync(WorksheetXml.EndRow); + await writer.WriteAsync(WorksheetXml.EndRow).ConfigureAwait(false); } #endif } maxRowIndex = currentRowIndex; - await writer.WriteAsync(WorksheetXml.EndSheetData); + await writer.WriteAsync(WorksheetXml.EndSheetData).ConfigureAwait(false); if (_configuration.AutoFilter) { - await writer.WriteAsync(WorksheetXml.Autofilter(GetDimensionRef(maxRowIndex, maxColumnIndex))); + await writer.WriteAsync(WorksheetXml.Autofilter(GetDimensionRef(maxRowIndex, maxColumnIndex))).ConfigureAwait(false); } - await writer.WriteAsync(WorksheetXml.Drawing(_currentSheetIndex)); - await writer.WriteAsync(WorksheetXml.EndWorksheet); + await writer.WriteAsync(WorksheetXml.Drawing(_currentSheetIndex)).ConfigureAwait(false); + await writer.WriteAsync(WorksheetXml.EndWorksheet).ConfigureAwait(false); if (_configuration.FastMode && dimensionPlaceholderPostition != 0) { - await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition); + await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition).ConfigureAwait(false); } if (_configuration.EnableAutoWidth) { - await OverwriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths?.Columns, cancellationToken); + await OverwriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths?.Columns, cancellationToken).ConfigureAwait(false); } if (_printHeader) @@ -325,10 +329,12 @@ private static async Task WriteColumnWidthPlaceholdersAsync( #else MiniExcelAsyncStreamWriter writer, #endif - int count) + int count, CancellationToken cancellationToken = default) { - var placeholderPosition = await writer.FlushAsync(); - await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(count)); + cancellationToken.ThrowIfCancellationRequested(); + + var placeholderPosition = await writer.FlushAsync().ConfigureAwait(false); + await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(count)).ConfigureAwait(false); return placeholderPosition; } @@ -342,13 +348,13 @@ private static async Task OverwriteColumnWidthPlaceholdersAsync( long placeholderPosition, IEnumerable columnWidths, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var position = await writer.FlushAsync(); + + var position = await writer.FlushAsync().ConfigureAwait(false); writer.SetPosition(placeholderPosition); - await WriteColumnsWidthsAsync(writer, columnWidths, cancellationToken); + await WriteColumnsWidthsAsync(writer, columnWidths, cancellationToken).ConfigureAwait(false); - await writer.FlushAsync(); + await writer.FlushAsync().ConfigureAwait(false); writer.SetPosition(position); } @@ -365,19 +371,19 @@ private static async Task WriteColumnsWidthsAsync( foreach (var column in columnWidths) { cancellationToken.ThrowIfCancellationRequested(); - + if (!hasWrittenStart) { - await writer.WriteAsync(WorksheetXml.StartCols); + await writer.WriteAsync(WorksheetXml.StartCols).ConfigureAwait(false); hasWrittenStart = true; } - await writer.WriteAsync(WorksheetXml.Column(column.Index, column.Width)); + await writer.WriteAsync(WorksheetXml.Column(column.Index, column.Width)).ConfigureAwait(false); } - + if (!hasWrittenStart) return; - - await writer.WriteAsync(WorksheetXml.EndCols); + + await writer.WriteAsync(WorksheetXml.EndCols).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -390,7 +396,7 @@ private async Task PrintHeaderAsync( List props, CancellationToken cancellationToken = default) { const int yIndex = 1; - await writer.WriteAsync(WorksheetXml.StartRow(yIndex)); + await writer.WriteAsync(WorksheetXml.StartRow(yIndex)).ConfigureAwait(false); var xIndex = 1; foreach (var p in props) @@ -402,12 +408,12 @@ private async Task PrintHeaderAsync( continue; var r = ExcelOpenXmlUtils.ConvertXyToCell(xIndex, yIndex); - await WriteCellAsync(writer, r, columnName: p.ExcelColumnName); + await WriteCellAsync(writer, r, columnName: p.ExcelColumnName).ConfigureAwait(false); } xIndex++; } - await writer.WriteAsync(WorksheetXml.EndRow); + await writer.WriteAsync(WorksheetXml.EndRow).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -419,7 +425,7 @@ private async Task WriteCellAsync( #endif string cellReference, string columnName) { - await writer.WriteAsync(WorksheetXml.Cell(cellReference, "str", GetCellXfId("1"), ExcelOpenXmlUtils.EncodeXML(columnName))); + await writer.WriteAsync(WorksheetXml.Cell(cellReference, "str", GetCellXfId("1"), ExcelOpenXmlUtils.EncodeXML(columnName))).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -450,7 +456,7 @@ value is DBNull || if (_configuration.EnableWriteNullValueCell && valueIsNull) { - await writer.WriteAsync(WorksheetXml.EmptyCell(columnReference, GetCellXfId("2"))); + await writer.WriteAsync(WorksheetXml.EmptyCell(columnReference, GetCellXfId("2"))).ConfigureAwait(false); return; } @@ -465,18 +471,18 @@ value is DBNull || var preserveSpace = cellValue != null && (cellValue.StartsWith(" ", StringComparison.Ordinal) || cellValue.EndsWith(" ", StringComparison.Ordinal)); - await writer.WriteAsync(WorksheetXml.Cell(columnReference, dataType, GetCellXfId(styleIndex), cellValue, preserveSpace: preserveSpace, columnType: columnType)); + await writer.WriteAsync(WorksheetXml.Cell(columnReference, dataType, GetCellXfId(styleIndex), cellValue, preserveSpace: preserveSpace, columnType: columnType)).ConfigureAwait(false); widthCollection?.AdjustWidth(cellIndex, cellValue); } [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateEndXmlAsync(CancellationToken cancellationToken) { - await AddFilesToZipAsync(cancellationToken); - await GenerateDrawinRelXmlAsync(cancellationToken); - await GenerateDrawingXmlAsync(cancellationToken); - await GenerateWorkbookXmlAsync(cancellationToken); - await GenerateContentTypesXmlAsync(cancellationToken); + await AddFilesToZipAsync(cancellationToken).ConfigureAwait(false); + await GenerateDrawinRelXmlAsync(cancellationToken).ConfigureAwait(false); + await GenerateDrawingXmlAsync(cancellationToken).ConfigureAwait(false); + await GenerateWorkbookXmlAsync(cancellationToken).ConfigureAwait(false); + await GenerateContentTypesXmlAsync(cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -485,7 +491,7 @@ private async Task AddFilesToZipAsync(CancellationToken cancellationToken) foreach (var item in _files) { cancellationToken.ThrowIfCancellationRequested(); - await CreateZipEntryAsync(item.Path, item.Byte, cancellationToken); + await CreateZipEntryAsync(item.Path, item.Byte, cancellationToken).ConfigureAwait(false); } } @@ -493,7 +499,7 @@ private async Task AddFilesToZipAsync(CancellationToken cancellationToken) private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + using (var context = new SheetStyleBuildContext(_zipDictionary, _archive, _utf8WithBom, _configuration.DynamicColumns)) { ISheetStyleBuilder builder = null; @@ -506,7 +512,7 @@ private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken) builder = new DefaultSheetStyleBuilder(context, _configuration.StyleOptions); break; } - var result = await builder.BuildAsync(cancellationToken); + var result = await builder.BuildAsync(cancellationToken).ConfigureAwait(false); _cellXfIdMap = result.CellXfIdMap; } } @@ -517,7 +523,7 @@ private async Task GenerateDrawinRelXmlAsync(CancellationToken cancellationToken for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) { cancellationToken.ThrowIfCancellationRequested(); - await GenerateDrawinRelXmlAsync(sheetIndex, cancellationToken); + await GenerateDrawinRelXmlAsync(sheetIndex, cancellationToken).ConfigureAwait(false); } } @@ -529,7 +535,7 @@ await CreateZipEntryAsync( ExcelFileNames.DrawingRels(sheetIndex), string.Empty, ExcelXml.DefaultDrawingXmlRels.Replace("{{format}}", drawing), - cancellationToken); + cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -538,7 +544,7 @@ private async Task GenerateDrawingXmlAsync(CancellationToken cancellationToken) for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) { cancellationToken.ThrowIfCancellationRequested(); - await GenerateDrawingXmlAsync(sheetIndex, cancellationToken); + await GenerateDrawingXmlAsync(sheetIndex, cancellationToken).ConfigureAwait(false); } } @@ -550,7 +556,7 @@ await CreateZipEntryAsync( ExcelFileNames.Drawing(sheetIndex), ExcelContentTypes.Drawing, ExcelXml.DefaultDrawing.Replace("{{format}}", drawing), - cancellationToken); + cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -569,38 +575,38 @@ await CreateZipEntryAsync( ExcelFileNames.SheetRels(sheetRelsXml.Key), null, ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value), - cancellationToken); + cancellationToken).ConfigureAwait(false); } await CreateZipEntryAsync( ExcelFileNames.Workbook, ExcelContentTypes.Workbook, ExcelXml.DefaultWorkbookXml.Replace("{{sheets}}", workbookXml.ToString()), - cancellationToken); + cancellationToken).ConfigureAwait(false); await CreateZipEntryAsync( ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()), - cancellationToken); + cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateContentTypesXmlAsync(CancellationToken cancellationToken) { var contentTypes = GetContentTypesXml(); - await CreateZipEntryAsync(ExcelFileNames.ContentTypes, null, contentTypes, cancellationToken); + await CreateZipEntryAsync(ExcelFileNames.ContentTypes, null, contentTypes, cancellationToken).ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + var contentTypesZipEntry = _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.ContentTypes); if (contentTypesZipEntry == null) { - await GenerateContentTypesXmlAsync(cancellationToken); + await GenerateContentTypesXmlAsync(cancellationToken).ConfigureAwait(false); return; } #if NET5_0_OR_GREATER @@ -609,20 +615,24 @@ private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToke using (var stream = contentTypesZipEntry.Open()) #endif { +#if NETCOREAPP2_0_OR_GREATER + var doc = await XDocument.LoadAsync(stream, LoadOptions.None, cancellationToken).ConfigureAwait(false); +#else var doc = XDocument.Load(stream); +#endif var ns = doc.Root?.GetDefaultNamespace(); var typesElement = doc.Descendants(ns + "Types").Single(); - + var partNames = new HashSet(StringComparer.InvariantCultureIgnoreCase); foreach (var partName in typesElement.Elements(ns + "Override").Select(s => s.Attribute("PartName").Value)) { partNames.Add(partName); } - + foreach (var p in _zipDictionary) { cancellationToken.ThrowIfCancellationRequested(); - + var partName = $"/{p.Key}"; if (!partNames.Contains(partName)) { @@ -630,16 +640,20 @@ private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToke typesElement.Add(newElement); } } - + stream.Position = 0; +#if NETCOREAPP2_0_OR_GREATER + await doc.SaveAsync(stream, SaveOptions.None, cancellationToken).ConfigureAwait(false); +#else doc.Save(stream); +#endif } } private async Task CreateZipEntryAsync(string path, string contentType, string content, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + var entry = _archive.CreateEntry(path, CompressionLevel.Fastest); #if NET5_0_OR_GREATER @@ -647,9 +661,9 @@ private async Task CreateZipEntryAsync(string path, string contentType, string c #else using (var zipStream = entry.Open()) #endif - using (var writer = new MiniExcelAsyncStreamWriter(zipStream, _utf8WithBom, _configuration.BufferSize, cancellationToken)) - await writer.WriteAsync(content); - + using (var writer = new MiniExcelAsyncStreamWriter(zipStream, _utf8WithBom, _configuration.BufferSize, cancellationToken)) + await writer.WriteAsync(content).ConfigureAwait(false); + if (!string.IsNullOrEmpty(contentType)) _zipDictionary.Add(path, new ZipPackageInfo(entry, contentType)); } @@ -657,15 +671,15 @@ private async Task CreateZipEntryAsync(string path, string contentType, string c private async Task CreateZipEntryAsync(string path, byte[] content, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + var entry = _archive.CreateEntry(path, CompressionLevel.Fastest); - + #if NET5_0_OR_GREATER await using (var zipStream = entry.Open()) #else using (var zipStream = entry.Open()) #endif - await zipStream.WriteAsync(content, 0, content.Length, cancellationToken); + await zipStream.WriteAsync(content, 0, content.Length, cancellationToken).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/MiniExcel/OpenXml/MiniExcelAsyncStreamWriter.cs b/src/MiniExcel/OpenXml/MiniExcelAsyncStreamWriter.cs index b2f8aff1..fb28e3e0 100644 --- a/src/MiniExcel/OpenXml/MiniExcelAsyncStreamWriter.cs +++ b/src/MiniExcel/OpenXml/MiniExcelAsyncStreamWriter.cs @@ -31,25 +31,25 @@ public async Task WriteAsync(string content) if (string.IsNullOrEmpty(content)) return; - await _streamWriter.WriteAsync(content); + await _streamWriter.WriteAsync(content).ConfigureAwait(false); } public async Task WriteAndFlushAsync(string content) { - await WriteAsync(content); - return await FlushAsync(); + await WriteAsync(content).ConfigureAwait(false); + return await FlushAsync().ConfigureAwait(false); } public async Task WriteWhitespaceAsync(int length) { - await _streamWriter.WriteAsync(new string(' ', length)); + await _streamWriter.WriteAsync(new string(' ', length)).ConfigureAwait(false); } public async Task FlushAsync() { _cancellationToken.ThrowIfCancellationRequested(); - await _streamWriter.FlushAsync(); + await _streamWriter.FlushAsync().ConfigureAwait(false); return _streamWriter.BaseStream.Position; } diff --git a/src/MiniExcel/Utils/calChainHelper.cs b/src/MiniExcel/Utils/calChainHelper.cs index c94c1886..d28ef5aa 100644 --- a/src/MiniExcel/Utils/calChainHelper.cs +++ b/src/MiniExcel/Utils/calChainHelper.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; @@ -31,7 +32,11 @@ public static async Task GenerateCalcChainSheetAsync(Stream calcChainStream, str { using (var writer = new StreamWriter(calcChainStream, Encoding.UTF8)) { - await writer.WriteAsync($"{calcChainContent}").ConfigureAwait(false); + await writer.WriteAsync($"{calcChainContent}" +#if NET7_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); } } } diff --git a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs index b7382576..40401ce6 100644 --- a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs @@ -1227,12 +1227,12 @@ await MiniExcel.SaveAsAsync(path.ToString(), new[] [Fact] public async Task ReadBigExcel_TakeCancel_Throws_TaskCanceledException() { - await Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { const string path = "../../../../../samples/xlsx/bigExcel.xlsx"; using var cts = new CancellationTokenSource(); - cts.CancelAsync(); + await cts.CancelAsync(); await using var stream = FileHelper.OpenRead(path); var rows = stream.QueryAsync(cancellationToken: cts.Token).ToBlockingEnumerable(cts.Token).ToList(); diff --git a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs index cf7a3972..a48ca63e 100644 --- a/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs +++ b/tests/MiniExcelTests/SaveByTemplate/MiniExcelTemplateAsyncTests.cs @@ -884,7 +884,7 @@ public async Task TemplateTest() public async Task SaveAsByTemplateAsync_TakeCancel_Throws_TaskCanceledException() { const string templatePath = "../../../../../samples/xlsx/TestTemplateEasyFill.xlsx"; - await Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { using var cts = new CancellationTokenSource(); using var path = AutoDeletingPath.Create(); From 8a7f175e7a64ab54c2de70eaa8b200046cdeffa3 Mon Sep 17 00:00:00 2001 From: Victor Irzak Date: Sun, 15 Jun 2025 21:01:35 -0400 Subject: [PATCH 21/25] Enforce .ConfigureAwait(false) and passing CancellationToken through .editorconfig on all async functions --- .editorconfig | 10 +- .../MiniExcel.Benchmarks.csproj | 1 + src/MiniExcel/Csv/CsvWriter.cs | 76 ++- src/MiniExcel/MiniExcel.cs | 18 +- .../OpenXml/ExcelOpenXmlSheetReader.cs | 6 +- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 19 +- .../Styles/DefaultSheetStyleBuilder.cs | 582 +++++++++--------- .../Styles/MinimalSheetStyleBuilder.cs | 56 +- .../OpenXml/Styles/SheetStyleBuildContext.cs | 8 +- .../OpenXml/Styles/SheetStyleBuilderBase.cs | 136 ++-- .../AsyncEnumerableWriteAdapter.cs | 8 +- .../MiniExcelDataReaderWriteAdapter.cs | 8 +- tests/MiniExcelTests/MiniExcelTests.csproj | 2 +- 13 files changed, 496 insertions(+), 434 deletions(-) diff --git a/.editorconfig b/.editorconfig index bc3e7b2e..588b3aea 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,4 +13,12 @@ dotnet_style_qualification_for_property = false dotnet_style_qualification_for_method = false # IDE0065: Misplaced using directive -csharp_using_directive_placement = outside_namespace \ No newline at end of file +csharp_using_directive_placement = outside_namespace + +dotnet_diagnostic.CA1835.severity = error + +# CA2007: Do not directly await a Task +dotnet_diagnostic.CA2007.severity = error + +# CA2016: Forward the CancellationToken parameter to methods that take one +dotnet_diagnostic.CA2016.severity = error diff --git a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj index e986cd38..e8f67aab 100644 --- a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj +++ b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj @@ -7,6 +7,7 @@ enable latest MiniExcelLibs.Benchmarks + $(NoWarn);CA2007 diff --git a/src/MiniExcel/Csv/CsvWriter.cs b/src/MiniExcel/Csv/CsvWriter.cs index efa46fd8..f7af71a6 100644 --- a/src/MiniExcel/Csv/CsvWriter.cs +++ b/src/MiniExcel/Csv/CsvWriter.cs @@ -115,22 +115,38 @@ private async Task WriteValuesAsync(StreamWriter writer, object values, str { writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration); } - var props = writeAdapter != null ? writeAdapter.GetColumns() : await asyncWriteAdapter.GetColumnsAsync(); + var props = writeAdapter != null ? writeAdapter.GetColumns() : await asyncWriteAdapter.GetColumnsAsync().ConfigureAwait(false); #else IMiniExcelWriteAdapter writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration); var props = writeAdapter.GetColumns(); #endif if (props == null) { - await _writer.WriteAsync(_configuration.NewLine); - await _writer.FlushAsync(); + await _writer.WriteAsync(_configuration.NewLine +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); + await _writer.FlushAsync( +#if NET8_0_OR_GREATER + cancellationToken +#endif + ).ConfigureAwait(false); return 0; } if (_printHeader) { - await _writer.WriteAsync(GetHeader(props)); - await _writer.WriteAsync(newLine); + await _writer.WriteAsync(GetHeader(props) +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); + await _writer.WriteAsync(newLine +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); } var rowBuilder = new StringBuilder(); @@ -148,8 +164,16 @@ private async Task WriteValuesAsync(StreamWriter writer, object values, str } RemoveTrailingSeparator(rowBuilder); - await _writer.WriteAsync(rowBuilder.ToString()); - await _writer.WriteAsync(newLine); + await _writer.WriteAsync(rowBuilder.ToString() +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); + await _writer.WriteAsync(newLine +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); rowsWritten++; } @@ -157,20 +181,28 @@ private async Task WriteValuesAsync(StreamWriter writer, object values, str #if NETSTANDARD2_0_OR_GREATER || NET else { - await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken)) + await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); rowBuilder.Clear(); - await foreach (var column in row) + await foreach (var column in row.ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); AppendColumn(rowBuilder, column); } RemoveTrailingSeparator(rowBuilder); - await _writer.WriteAsync(rowBuilder.ToString()); - await _writer.WriteAsync(newLine); + await _writer.WriteAsync(rowBuilder.ToString() +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); + await _writer.WriteAsync(newLine +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); rowsWritten++; } @@ -188,20 +220,32 @@ public async Task SaveAsAsync(CancellationToken cancellationToken = defau if (_value == null) { - await _writer.WriteAsync(""); - await _writer.FlushAsync(); + await _writer.WriteAsync("" +#if NET5_0_OR_GREATER + .AsMemory(), cancellationToken +#endif + ).ConfigureAwait(false); + await _writer.FlushAsync( +#if NET8_0_OR_GREATER + cancellationToken +#endif + ).ConfigureAwait(false); return new int[0]; } - var rowsWritten = await WriteValuesAsync(_writer, _value, seperator, newLine, cancellationToken); - await _writer.FlushAsync(); + var rowsWritten = await WriteValuesAsync(_writer, _value, seperator, newLine, cancellationToken).ConfigureAwait(false); + await _writer.FlushAsync( +#if NET8_0_OR_GREATER + cancellationToken +#endif + ).ConfigureAwait(false); return new[] { rowsWritten }; } public async Task InsertAsync(bool overwriteSheet = false, CancellationToken cancellationToken = default) { - var rowsWritten = await SaveAsAsync(cancellationToken); + var rowsWritten = await SaveAsAsync(cancellationToken).ConfigureAwait(false); return rowsWritten.FirstOrDefault(); } diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index 35ffd4e1..302f3173 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -67,7 +67,7 @@ public static async Task InsertAsync(string path, object value, string shee } [Zomp.SyncMethodGenerator.CreateSyncVersion] - public static async Task InsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default) + public static async Task InsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default) { stream.Seek(0, SeekOrigin.End); if (excelType == ExcelType.CSV) @@ -169,7 +169,7 @@ public static async IAsyncEnumerable QueryRangeAsync(this Stream stream public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - await foreach(var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) + await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) yield return item; } @@ -257,7 +257,7 @@ public async static Task QueryAsDataTableAsync(this Stream stream, bo var dt = new DataTable(sheetName); var first = true; var provider = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false); - var rows = provider.QueryAsync(false, sheetName, startCell); + var rows = provider.QueryAsync(false, sheetName, startCell, cancellationToken).ConfigureAwait(false); var columnDict = new Dictionary(); await foreach (IDictionary row in rows.WithCancellation(cancellationToken).ConfigureAwait(false)) @@ -302,7 +302,7 @@ public static async Task> GetSheetNamesAsync(string path, OpenXmlCo return await GetSheetNamesAsync(stream, config, cancellationToken).ConfigureAwait(false); } - [Zomp.SyncMethodGenerator.CreateSyncVersion] + [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async Task> GetSheetNamesAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default) { config = config ?? OpenXmlConfiguration.DefaultConfig; @@ -341,9 +341,11 @@ public static async Task> GetColumnsAsync(string path, bool [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async Task> GetColumnsAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default) { - var enumerator = QueryAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration).GetAsyncEnumerator(cancellationToken); +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task + await using var enumerator = QueryAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration, cancellationToken).GetAsyncEnumerator(cancellationToken); +#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task _ = enumerator.ConfigureAwait(false); - if (!await enumerator.MoveNextAsync()) + if (!await enumerator.MoveNextAsync().ConfigureAwait(false)) { return null; } @@ -377,7 +379,7 @@ public static async Task ConvertCsvToXlsxAsync(string csv, string xlsx, Cancella [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async Task ConvertCsvToXlsxAsync(Stream csv, Stream xlsx, CancellationToken cancellationToken = default) { - var value = QueryAsync(csv, useHeaderRow: false, excelType: ExcelType.CSV); + var value = QueryAsync(csv, useHeaderRow: false, excelType: ExcelType.CSV, cancellationToken: cancellationToken); await SaveAsAsync(xlsx, value, printHeader: false, excelType: ExcelType.XLSX, cancellationToken: cancellationToken).ConfigureAwait(false); } @@ -392,7 +394,7 @@ public static async Task ConvertXlsxToCsvAsync(string xlsx, string csv, Cancella [Zomp.SyncMethodGenerator.CreateSyncVersion] public static async Task ConvertXlsxToCsvAsync(Stream xlsx, Stream csv, CancellationToken cancellationToken = default) { - var value = QueryAsync(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX); + var value = QueryAsync(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX, cancellationToken: cancellationToken); await SaveAsAsync(csv, value, printHeader: false, excelType: ExcelType.CSV, cancellationToken: cancellationToken).ConfigureAwait(false); } } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs index 894516ae..d5cbd84f 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs @@ -55,7 +55,7 @@ public IAsyncEnumerable> QueryAsync(bool useHeaderRo //Todo: Find a way if possible to remove the 'hasHeader' parameter to check whether or not to include // the first row in the result set in favor of modifying the already present 'useHeaderRow' to do the same job - return QueryImplAsync(QueryAsync(false, sheetName, startCell, cancellationToken), startCell, hasHeader, _config); + return QueryImplAsync(QueryAsync(false, sheetName, startCell, cancellationToken), startCell, hasHeader, _config, cancellationToken); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -92,7 +92,7 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea [Zomp.SyncMethodGenerator.CreateSyncVersion] public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { - return QueryImplAsync(QueryRangeAsync(false, sheetName, startCell, endCell, cancellationToken), startCell, hasHeader, this._config); + return QueryImplAsync(QueryRangeAsync(false, sheetName, startCell, endCell, cancellationToken), startCell, hasHeader, this._config, cancellationToken); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -137,7 +137,7 @@ public IAsyncEnumerable> QueryRangeAsync(bool useHea [Zomp.SyncMethodGenerator.CreateSyncVersion] public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new() { - return QueryImplAsync(QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config); + return QueryImplAsync(QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config, cancellationToken); } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index bcd5a3bd..8cea4bba 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -111,7 +111,7 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToke _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels)?.Delete(); await CreateZipEntryAsync(ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()), cancellationToken).ConfigureAwait(false); - await InsertContentTypesXmlAsync(cancellationToken); + await InsertContentTypesXmlAsync(cancellationToken).ConfigureAwait(false); return rowsWritten; } @@ -167,7 +167,7 @@ MiniExcelAsyncStreamWriter writer ) { var dimensionPlaceholderPostition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension).ConfigureAwait(false); - await writer.WriteAsync(WorksheetXml.DimensionPlaceholder); // end of code will be replaced + await writer.WriteAsync(WorksheetXml.DimensionPlaceholder).ConfigureAwait(false); // end of code will be replaced return dimensionPlaceholderPostition; } @@ -251,7 +251,7 @@ private async Task WriteValuesAsync( } else { - await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props), cancellationToken); + await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props), cancellationToken).ConfigureAwait(false); } //header @@ -273,7 +273,7 @@ private async Task WriteValuesAsync( foreach (var cellValue in row) { cancellationToken.ThrowIfCancellationRequested(); - await WriteCellAsync(writer, currentRowIndex, cellValue.CellIndex, cellValue.Value, cellValue.Prop, widths); + await WriteCellAsync(writer, currentRowIndex, cellValue.CellIndex, cellValue.Value, cellValue.Prop, widths).ConfigureAwait(false); } await writer.WriteAsync(WorksheetXml.EndRow).ConfigureAwait(false); } @@ -281,7 +281,7 @@ private async Task WriteValuesAsync( else { #if !SYNC_ONLY - await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken)) + await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); await writer.WriteAsync(WorksheetXml.StartRow(++currentRowIndex)).ConfigureAwait(false); @@ -610,7 +610,9 @@ private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToke return; } #if NET5_0_OR_GREATER +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await using (var stream = contentTypesZipEntry.Open()) +#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task #else using (var stream = contentTypesZipEntry.Open()) #endif @@ -657,7 +659,9 @@ private async Task CreateZipEntryAsync(string path, string contentType, string c var entry = _archive.CreateEntry(path, CompressionLevel.Fastest); #if NET5_0_OR_GREATER +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await using (var zipStream = entry.Open()) +#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task #else using (var zipStream = entry.Open()) #endif @@ -675,11 +679,14 @@ private async Task CreateZipEntryAsync(string path, byte[] content, Cancellation var entry = _archive.CreateEntry(path, CompressionLevel.Fastest); #if NET5_0_OR_GREATER +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await using (var zipStream = entry.Open()) + await zipStream.WriteAsync(content, cancellationToken).ConfigureAwait(false); +#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task #else using (var zipStream = entry.Open()) -#endif await zipStream.WriteAsync(content, 0, content.Length, cancellationToken).ConfigureAwait(false); +#endif } } } \ No newline at end of file diff --git a/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs b/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs index da0dfb7a..dbb95e0d 100644 --- a/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs +++ b/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs @@ -40,10 +40,10 @@ protected override async Task GenerateNumFmtAsync() /* * * */ - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "font", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "vertAlign", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "baseline"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "sz", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "11"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "name", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "Calibri"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "family", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "2"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "font", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "vertAlign", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "baseline").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "sz", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "11").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "name", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "Calibri").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "family", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "2").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); /* * @@ -86,23 +86,23 @@ protected override async Task GenerateFontAsync() * * */ - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "font", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "vertAlign", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "baseline"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "sz", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "11"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FFFFFFFF"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "name", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "Calibri"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "family", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "2"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "font", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "vertAlign", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "baseline").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "sz", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "11").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FFFFFFFF").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "name", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "Calibri").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "family", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "val", null, "2").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -113,22 +113,22 @@ protected override async Task GenerateFillAsync() * * */ - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "patternType", null, "none"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "patternType", null, "none").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); /* * * * */ - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "patternType", null, "gray125"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "patternType", null, "gray125").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); /* * @@ -137,14 +137,14 @@ protected override async Task GenerateFillAsync() * * */ - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "patternType", null, "solid"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fgColor", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "284472C4"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fill", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "patternFill", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "patternType", null, "solid").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "fgColor", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "284472C4").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -169,40 +169,40 @@ protected override async Task GenerateBorderAsync() * * */ - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "border", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalUp", null, "0"); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalDown", null, "0"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "left", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "right", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "top", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "bottom", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "diagonal", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "border", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalUp", null, "0").ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalDown", null, "0").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "left", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "right", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "top", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "bottom", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "diagonal", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); /* * @@ -223,40 +223,40 @@ protected override async Task GenerateBorderAsync() * * */ - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "border", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalUp", null, "0"); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalDown", null, "0"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "left", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "right", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "top", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "bottom", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "diagonal", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none"); - await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI); - await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000"); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); - await _context.NewXmlWriter.WriteEndElementAsync(); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "border", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalUp", null, "0").ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "diagonalDown", null, "0").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "left", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "right", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "top", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "bottom", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "thin").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "diagonal", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "style", null, "none").ConfigureAwait(false); + await _context.NewXmlWriter.WriteStartElementAsync(_context.OldXmlReader.Prefix, "color", _context.OldXmlReader.NamespaceURI).ConfigureAwait(false); + await _context.NewXmlWriter.WriteAttributeStringAsync(null, "rgb", null, "FF000000").ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); + await _context.NewXmlWriter.WriteEndElementAsync().ConfigureAwait(false); } [Zomp.SyncMethodGenerator.CreateSyncVersion] @@ -267,63 +267,63 @@ protected override async Task GenerateCellStyleXfAsync() *