diff --git a/.editorconfig b/.editorconfig index bc3e7b2e..68c52882 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,4 +13,18 @@ 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 + +# CA1835: Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes +dotnet_diagnostic.CA1835.severity = error + +# CA1849: Call async methods when in an async method +dotnet_diagnostic.CA1849.severity = error + +dotnet_diagnostic.CA2000.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..3459b9fb 100644 --- a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj +++ b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj @@ -7,6 +7,7 @@ enable latest MiniExcelLibs.Benchmarks + $(NoWarn);CA2000;CA2007 diff --git a/src/MiniExcel/Csv/CsvReader.cs b/src/MiniExcel/Csv/CsvReader.cs index 39562333..dddec16d 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,8 +23,11 @@ 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 cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (startCell != "A1") throw new NotImplementedException("CSV does not implement parameter startCell"); @@ -35,14 +39,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 +cancellationToken +#endif + ).ConfigureAwait(false)) != 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 +cancellationToken +#endif + ).ConfigureAwait(false); if (nextPart == null) { break; @@ -107,62 +119,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 cancellationToken = default) where T : class, new() { - var dynamicRecords = Query(false, sheetName, startCell); - return ExcelOpenXmlSheetReader.QueryImpl(dynamicRecords, startCell, hasHeader, _config); + var dynamicRecords = QueryAsync(false, sheetName, startCell, cancellationToken); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, _config, cancellationToken); } - 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 cancellationToken = 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 cancellationToken = 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, cancellationToken); + return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, this._config, cancellationToken); } - 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 cancellationToken = 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() - { - 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() + [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 await Task.Run(() => QueryRange(sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, hasHeader), cancellationToken).ConfigureAwait(false); + 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/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/ExcelFactory.cs b/src/MiniExcel/ExcelFactory.cs index 36760508..a07b4d3d 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 cancellationToken = default) { switch (excelType) { case ExcelType.CSV: return new CsvReader(stream, configuration); case ExcelType.XLSX: - return new ExcelOpenXmlSheetReader(stream, configuration); + 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/IExcelReader.cs b/src/MiniExcel/IExcelReader.cs index 0581cd34..eb8e2010 100644 --- a/src/MiniExcel/IExcelReader.cs +++ b/src/MiniExcel/IExcelReader.cs @@ -1,23 +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(); - 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(); - 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(); + [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(); + [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(); } } 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 deleted file mode 100644 index 51ede3f3..00000000 --- a/src/MiniExcel/MiniExcel.Async.cs +++ /dev/null @@ -1,160 +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, cancellationToken: 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); - } - } - - 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> 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 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() - { - return await ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).QueryAsync(sheetName, startCell, hasHeader, cancellationToken).ConfigureAwait(false); - } - - 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); - } - - 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. - /// - [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 03470dbd..047f9010 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -10,20 +10,25 @@ using System.Dynamic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; 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 cancellationToken = default, params MiniExcelPicture[] images) { using (var stream = File.Open(path, FileMode.OpenOrCreate)) - MiniExcelPictureImplement.AddPicture(stream, images); + await MiniExcelPictureImplement.AddPictureAsync(stream, cancellationToken, images).ConfigureAwait(false); } - public static void AddPicture(Stream excelStream, params MiniExcelPicture[] images) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task AddPicture(Stream excelStream, CancellationToken cancellationToken = default, params MiniExcelPicture[] images) { - MiniExcelPictureImplement.AddPicture(excelStream, images); + 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) @@ -37,83 +42,94 @@ 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 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 = SaveAs(path, value, printHeader, sheetName, excelType, configuration); + 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 Insert(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet); + 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 Insert(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet); + return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken).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] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "TODO: CsvWriter needs to be disposed")] + 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 ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).Insert(overwriteSheet); + var provider = ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false); + return await provider.InsertAsync(overwriteSheet, cancellationToken).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, cancellationToken).ConfigureAwait(false); } } - 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 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 SaveAs(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration); + return await SaveAsAsync(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, cancellationToken).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] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "TODO: CsvWriter needs to be disposed")] + 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 ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAs(); + return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(cancellationToken).ConfigureAwait(false); } - 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 cancellationToken = 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, 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 } - 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 cancellationToken = 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)) + 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).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 cancellationToken = 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, cancellationToken).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 cancellationToken = default) { - using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration)) - foreach (var item in excelReader.Query(useHeaderRow, sheetName, startCell)) + 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).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } @@ -135,76 +151,87 @@ public static IEnumerable Query(this Stream stream, bool useHeaderRow = /// 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 cancellationToken = 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, cancellationToken).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 cancellationToken = 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, cancellationToken).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startCell, endCell, cancellationToken).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 cancellationToken = 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, cancellationToken).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 cancellationToken = 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, cancellationToken).ConfigureAwait(false)) + await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken).ConfigureAwait(false)) yield return item.Aggregate(new ExpandoObject() as IDictionary, (dict, p) => { dict.Add(p); return dict; }); } #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 cancellationToken = default) { using (var stream = File.Create(path)) - SaveAsByTemplate(stream, templatePath, value, configuration); + await SaveAsByTemplateAsync(stream, templatePath, value, configuration, cancellationToken).ConfigureAwait(false); } - 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 cancellationToken = default) { using (var stream = File.Create(path)) - SaveAsByTemplate(stream, templateBytes, value, configuration); + await SaveAsByTemplateAsync(stream, templateBytes, value, configuration, cancellationToken).ConfigureAwait(false); } - 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 cancellationToken = default) { - ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templatePath, value); + await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, cancellationToken).ConfigureAwait(false); } - 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 cancellationToken = default) { - ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templateBytes, value); + await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, cancellationToken).ConfigureAwait(false); } #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 cancellationToken = default) { using (var stream = File.Create(mergedFilePath)) - MergeSameCells(stream, path, excelType, configuration); + await MergeSameCellsAsync(stream, path, excelType, configuration, cancellationToken).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 cancellationToken = default) { - ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(path); + await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, cancellationToken).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 cancellationToken = default) { - ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(filePath); + await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(filePath, cancellationToken).ConfigureAwait(false); } #endregion @@ -213,25 +240,30 @@ public static void MergeSameCells(this Stream stream, byte[] filePath, ExcelType /// 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 cancellationToken = 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, cancellationToken).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 cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/ - sheetName = stream.GetSheetNames(configuration as OpenXmlConfiguration).First(); + sheetName = (await stream.GetSheetNamesAsync(configuration as OpenXmlConfiguration, cancellationToken).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, cancellationToken).ConfigureAwait(false); + var rows = provider.QueryAsync(false, sheetName, startCell, cancellationToken).ConfigureAwait(false); var columnDict = new Dictionary(); - foreach (IDictionary row in rows) + await foreach (IDictionary row in rows.WithCancellation(cancellationToken).ConfigureAwait(false)) { if (first) { @@ -266,82 +298,110 @@ 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 cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetSheetNames(stream, config); + return await GetSheetNamesAsync(stream, config, cancellationToken).ConfigureAwait(false); } - 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 cancellationToken = default) { config = config ?? OpenXmlConfiguration.DefaultConfig; + // For some reason this breaks the tests +#pragma warning disable CA2000 // Dispose objects before losing scope var archive = new ExcelOpenXmlZip(stream); - return new ExcelOpenXmlSheetReader(stream, config).GetWorkbookRels(archive.entries).Select(s => s.Name).ToList(); +#pragma warning restore CA2000 // Dispose objects before losing scope + using 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(); } - public static List GetSheetInformations(string path, OpenXmlConfiguration config = null) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetInformationsAsync(string path, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetSheetInformations(stream, config); + return await GetSheetInformationsAsync(stream, config, cancellationToken).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 cancellationToken = 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(); + using var archive = new ExcelOpenXmlZip(stream); + using 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(); } - 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 cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetColumns(stream, useHeaderRow, sheetName, excelType, startCell, configuration); + return await GetColumnsAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration, cancellationToken).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 cancellationToken = default) { - return (Query(stream, useHeaderRow, sheetName, excelType, startCell, configuration).FirstOrDefault() as IDictionary)?.Keys; +#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().ConfigureAwait(false)) + { + 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 cancellationToken = default) { using (var stream = FileHelper.OpenSharedRead(path)) - return GetSheetDimensions(stream); + return await GetSheetDimensionsAsync(stream, cancellationToken).ConfigureAwait(false); } - public static IList GetSheetDimensions(this Stream stream) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task> GetSheetDimensionsAsync(this Stream stream, CancellationToken cancellationToken = default) { - return new ExcelOpenXmlSheetReader(stream, null).GetDimensions(); + using var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, null, cancellationToken: cancellationToken).ConfigureAwait(false); + return await reader.GetDimensionsAsync(cancellationToken).ConfigureAwait(false); } - public static void ConvertCsvToXlsx(string csv, string xlsx) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + 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)) { - ConvertCsvToXlsx(csvStream, xlsxStream); + await ConvertCsvToXlsxAsync(csvStream, xlsxStream, cancellationToken: cancellationToken).ConfigureAwait(false); } } - public static void ConvertCsvToXlsx(Stream csv, Stream xlsx) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ConvertCsvToXlsxAsync(Stream csv, Stream xlsx, CancellationToken cancellationToken = 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, cancellationToken: cancellationToken); + await SaveAsAsync(xlsx, value, printHeader: false, excelType: ExcelType.XLSX, cancellationToken: cancellationToken).ConfigureAwait(false); } - public static void ConvertXlsxToCsv(string xlsx, string csv) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + 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)) - ConvertXlsxToCsv(xlsxStream, csvStream); + await ConvertXlsxToCsvAsync(xlsxStream, csvStream, cancellationToken).ConfigureAwait(false); } - public static void ConvertXlsxToCsv(Stream xlsx, Stream csv) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task ConvertXlsxToCsvAsync(Stream xlsx, Stream csv, CancellationToken cancellationToken = default) { - var value = Query(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX); - SaveAs(csv, value, printHeader: false, excelType: ExcelType.CSV); + var value = QueryAsync(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX, cancellationToken: cancellationToken); + await SaveAsAsync(csv, value, printHeader: false, excelType: ExcelType.CSV, cancellationToken: cancellationToken).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj index eb4a83c6..f40c18ac 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,10 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true - + + + + 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..dc8b81f3 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,37 +27,42 @@ 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 - }; - - 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(); } - public IEnumerable> Query(bool useHeaderRow, string sheetName, string startCell) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public static async Task CreateAsync(Stream stream, IConfiguration configuration, bool isUpdateMode = true, CancellationToken cancellationToken = default) { - return QueryRange(useHeaderRow, sheetName, startCell, ""); + var reader = new ExcelOpenXmlSheetReader(stream, configuration, isUpdateMode); + await reader.SetSharedStringsAsync(cancellationToken).ConfigureAwait(false); + return reader; } - public IEnumerable Query(string sheetName, string startCell, bool hasHeader) where T : class, new() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default) + { + return QueryRangeAsync(useHeaderRow, sheetName, startCell, "", cancellationToken); + } + + [Zomp.SyncMethodGenerator.CreateSyncVersion] + 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 QueryImpl(Query(false, sheetName, startCell), startCell, hasHeader, _config); + return QueryImplAsync(QueryAsync(false, sheetName, startCell, cancellationToken), startCell, hasHeader, _config, cancellationToken); } - 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 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."); @@ -80,16 +86,20 @@ 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, cancellationToken); } - 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 cancellationToken = default) where T : class, new() { - return QueryImpl(QueryRange(false, sheetName, startCell, endCell), startCell, hasHeader, this._config); + return QueryImplAsync(QueryRangeAsync(false, sheetName, startCell, endCell, cancellationToken), startCell, hasHeader, this._config, cancellationToken); } - 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 cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (startRowIndex <= 0) { throw new ArgumentOutOfRangeException(nameof(startRowIndex), "Start row index is 1-based and must be greater than 0."); @@ -121,50 +131,71 @@ public IEnumerable> QueryRange(bool useHeaderRow, st endColumnIndex--; } - return InternalQueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex); + return InternalQueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken); } - 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 cancellationToken = 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, cancellationToken), ReferenceHelper.ConvertXyToCell(startColumnIndex, startRowIndex), hasHeader, _config, cancellationToken); } - 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 cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + var sheetEntry = GetSheetEntry(sheetName); // 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, cancellationToken).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, cancellationToken).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; } 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, cancellationToken).ConfigureAwait(false)) yield break; while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; var headRows = new Dictionary(); @@ -182,8 +213,8 @@ internal IEnumerable> InternalQueryRange(bool useHea if (rowIndex < startRowIndex) { - XmlReaderHelper.ReadFirstContent(reader); - XmlReaderHelper.SkipToNextSameLevelDom(reader); + await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false); + await XmlReaderHelper.SkipToNextSameLevelDomAsync(reader, cancellationToken).ConfigureAwait(false); continue; } if (endRowIndex.HasValue && rowIndex > endRowIndex.Value) @@ -205,7 +236,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, cancellationToken).ConfigureAwait(false) && !_config.IgnoreEmptyRows) { //Fill in case of self closed empty row tag eg. yield return GetCell(useHeaderRow, maxColumnIndex, headRows, startColumnIndex); @@ -223,8 +254,11 @@ internal IEnumerable> InternalQueryRange(bool useHea 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, cancellationToken).ConfigureAwait(false); + + var cellValue = cellAndColumn.CellValue; + columnIndex = cellAndColumn.ColumnIndex; if (_config.FillMergedCells) { @@ -257,7 +291,7 @@ internal IEnumerable> InternalQueryRange(bool useHea SetCellsValueAndHeaders(cellValue, useHeaderRow, ref headRows, ref isFirstRow, ref cell, columnIndex); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; } @@ -272,13 +306,13 @@ internal IEnumerable> InternalQueryRange(bool useHea yield return cell; } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -286,8 +320,11 @@ 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 cancellationToken = default) where T : class, new() { + cancellationToken.ThrowIfCancellationRequested(); + var type = typeof(T); //TODO:need to optimize @@ -297,7 +334,7 @@ internal IEnumerable> InternalQueryRange(bool useHea var first = true; var rowIndex = 0; - foreach (var item in values) + await foreach (var item in values.ConfigureAwait(false)) { if (first) { @@ -354,7 +391,7 @@ internal IEnumerable> InternalQueryRange(bool useHea yield return v; } } - + private ZipArchiveEntry GetSheetEntry(string sheetName) { // if sheets count > 1 need to read xl/_rels/workbook.xml.rels @@ -417,8 +454,11 @@ private static void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, } } - private void SetSharedStrings() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task SetSharedStringsAsync(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + if (_sharedStrings != null) return; var sharedStringsEntry = _archive.GetEntry("xl/sharedStrings.xml"); @@ -430,12 +470,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, cancellationToken, _ns).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, cancellationToken, _ns).ConfigureAwait(false)) + { + list.Add(str); + } + _sharedStrings = list.ToDictionary((x) => idx++, x => x); } } } @@ -447,15 +492,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 cancellationToken = default) { + var xmlSettings = XmlReaderHelper.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, cancellationToken).ConfigureAwait(false)) yield break; var activeSheetIndex = 0; @@ -463,7 +518,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 cancellationToken = default) { - var sheetRecords = ReadWorkbook(entries).ToList(); + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + + var sheetRecords = new List(); + await foreach (var sheetRecord in ReadWorkbookAsync(entries, cancellationToken).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, cancellationToken).ConfigureAwait(false)) return null; while (!reader.EOF) @@ -545,9 +621,13 @@ internal List GetWorkbookRels(ReadOnlyCollection e } } - reader.Skip(); + await reader.SkipAsync() +#if NET6_0_OR_GREATER + .WaitAsync(cancellationToken) +#endif + .ConfigureAwait(false); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -557,8 +637,23 @@ 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 cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + const int xfIndex = -1; int newColumnIndex; @@ -575,41 +670,45 @@ private object ReadCellAndSetColumnIndex(XmlReader reader, ref int columnIndex, if (columnIndex < startColumnIndex) { - if (!XmlReaderHelper.ReadFirstContent(reader)) - return null; + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) + return new CellAndColumn(null, columnIndex); while (!reader.EOF) - if (!XmlReaderHelper.SkipContent(reader)) + if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; - return null; + return new CellAndColumn(null, columnIndex); } - if (!XmlReaderHelper.ReadFirstContent(reader)) - return null; + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) + return new CellAndColumn(null, columnIndex); object value = null; while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "v", _ns)) { - var rawValue = reader.ReadElementContentAsString(); + var rawValue = await reader.ReadElementContentAsStringAsync() +#if NET6_0_OR_GREATER + .WaitAsync(cancellationToken) +#endif + .ConfigureAwait(false); if (!string.IsNullOrEmpty(rawValue)) ConvertCellValue(rawValue, aT, xfIndex, out value); } else if (XmlReaderHelper.IsStartElement(reader, "is", _ns)) { - var rawValue = StringHelper.ReadStringItem(reader); + var rawValue = await StringHelper.ReadStringItemAsync(reader,cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(rawValue)) ConvertCellValue(rawValue, aT, xfIndex, out value); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } - return value; + return new CellAndColumn(value, columnIndex); } private void ConvertCellValue(string rawValue, string aT, int xfIndex, out object value) @@ -693,8 +792,19 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec } } - internal IList GetDimensions() + [Zomp.SyncMethodGenerator.CreateSyncVersion] + internal async Task> GetDimensionsAsync(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + + var xmlSettings = XmlReaderHelper.GetXmlReaderSettings( +#if SYNC_ONLY + false +#else + true +#endif + ); + var ranges = new List(); var sheets = _archive.entries.Where(e => @@ -712,9 +822,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)) { @@ -760,19 +870,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, cancellationToken).ConfigureAwait(false)) 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, cancellationToken).ConfigureAwait(false)) continue; while (!reader.EOF) @@ -781,7 +891,7 @@ internal IList GetDimensions() { maxRowIndex++; - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; var cellIndex = -1; @@ -793,17 +903,17 @@ internal IList GetDimensions() maxColumnIndex = Math.Max(maxColumnIndex, cellIndex); } - if (!XmlReaderHelper.SkipContent(reader)) + if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -822,15 +932,52 @@ internal IList GetDimensions() return ranges; } - internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out bool withoutCR, out int maxRowIndex, out int maxColumnIndex) + internal class GetMaxRowColumnIndexResult { - withoutCR = false; - maxRowIndex = -1; - maxColumnIndex = -1; + 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 cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + var xmlSettings = XmlReaderHelper.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(cancellationToken) +#endif + .ConfigureAwait(false)) { if (XmlReaderHelper.IsStartElement(reader, "c", _ns)) { @@ -874,19 +1021,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, cancellationToken).ConfigureAwait(false)) + return new GetMaxRowColumnIndexResult(false); while (!reader.EOF) { if (XmlReaderHelper.IsStartElement(reader, "sheetData", _ns)) { - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; while (!reader.EOF) @@ -895,7 +1042,7 @@ internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out boo { maxRowIndex++; - if (!XmlReaderHelper.ReadFirstContent(reader)) + if (!await XmlReaderHelper.ReadFirstContentAsync(reader, cancellationToken).ConfigureAwait(false)) continue; // Cells @@ -908,17 +1055,17 @@ internal static bool TryGetMaxRowColumnIndex(ZipArchiveEntry sheetEntry, out boo maxColumnIndex = Math.Max(maxColumnIndex, cellIndex); } - if (!XmlReaderHelper.SkipContent(reader)) + if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) break; } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } @@ -926,26 +1073,53 @@ 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 cancellationToken = default) { - mergeCells = new MergeCells(); + cancellationToken.ThrowIfCancellationRequested(); + + var xmlSettings = XmlReaderHelper.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, cancellationToken).ConfigureAwait(false)) + return new MergeCellsResult(false); while (!reader.EOF) { @@ -973,15 +1147,15 @@ internal static bool TryGetMergeCells(ZipArchiveEntry sheetEntry, out MergeCells } } - XmlReaderHelper.SkipContent(reader); + await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false); } - else if (!XmlReaderHelper.SkipContent(reader)) + else if (!await XmlReaderHelper.SkipContentAsync(reader, cancellationToken).ConfigureAwait(false)) { break; } } } - return true; + return new MergeCellsResult(true, mergeCells); } } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 85633cbf..8c21ab64 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -17,11 +17,14 @@ namespace MiniExcelLibs.OpenXml { internal partial class ExcelOpenXmlSheetWriter : IExcelWriter { + [Zomp.SyncMethodGenerator.CreateSyncVersion] public async Task SaveAsAsync(CancellationToken cancellationToken = default) { try { - await GenerateDefaultOpenXmlAsync(cancellationToken); + cancellationToken.ThrowIfCancellationRequested(); + + await GenerateDefaultOpenXmlAsync(cancellationToken).ConfigureAwait(false); var sheets = GetSheets(); var rowsWritten = new List(); @@ -29,14 +32,14 @@ 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); + 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,16 +48,20 @@ public async Task SaveAsAsync(CancellationToken cancellationToken = defau } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] public async Task InsertAsync(bool overwriteSheet = false, CancellationToken cancellationToken = default) { try { + cancellationToken.ThrowIfCancellationRequested(); + if (!_configuration.FastMode) throw new InvalidOperationException("Insert requires fast mode to be enabled"); cancellationToken.ThrowIfCancellationRequested(); - - var sheetRecords = new ExcelOpenXmlSheetReader(_stream, _configuration).GetWorkbookRels(_archive.Entries).ToArray(); + + using 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)) { cancellationToken.ThrowIfCancellationRequested(); @@ -64,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) @@ -73,38 +80,38 @@ 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); + await InsertContentTypesXmlAsync(cancellationToken).ConfigureAwait(false); return rowsWritten; } @@ -114,30 +121,31 @@ 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)); @@ -146,33 +154,53 @@ 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); } - 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 + var dimensionPlaceholderPostition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension).ConfigureAwait(false); + await writer.WriteAsync(WorksheetXml.DimensionPlaceholder).ConfigureAwait(false); // end of code will be replaced 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(); + 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); } - private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, object values, CancellationToken cancellationToken) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task WriteValuesAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + object values, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - -#if NETSTANDARD2_0_OR_GREATER || NET + IMiniExcelWriteAdapter writeAdapter = null; if (!MiniExcelWriteAdapterFactory.TryGetAsyncWriteAdapter(values, _configuration, out var asyncWriteAdapter)) { @@ -181,59 +209,57 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje 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 - IMiniExcelWriteAdapter writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration); - - var isKnownCount = writeAdapter.TryGetKnownCount(out var count); - var props = writeAdapter.GetColumns(); + props = writeAdapter != null ? writeAdapter?.GetColumns() : await asyncWriteAdapter.GetColumnsAsync().ConfigureAwait(false); #endif - if (props == null) { - await WriteEmptySheetAsync(writer); + await WriteEmptySheetAsync(writer).ConfigureAwait(false); return 0; } - var maxColumnIndex = props.Count; 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; // 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))).ConfigureAwait(false); } - 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).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, props); + columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, maxColumnIndex, cancellationToken).ConfigureAwait(false); widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props); } else { - await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props), cancellationToken); + await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props), cancellationToken).ConfigureAwait(false); } //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++; } @@ -242,136 +268,180 @@ private async Task WriteValuesAsync(MiniExcelAsyncStreamWriter writer, obje 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 WriteCellAsync(writer, currentRowIndex, cellValue.CellIndex, cellValue.Value, cellValue.Prop, widths).ConfigureAwait(false); } - await writer.WriteAsync(WorksheetXml.EndRow); + await writer.WriteAsync(WorksheetXml.EndRow).ConfigureAwait(false); } } -#if NETSTANDARD2_0_OR_GREATER || NET else { - await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken)) +#if !SYNC_ONLY + await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken).ConfigureAwait(false)) { 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.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.Drawing(_currentSheetIndex)); - 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.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); } - var toSubtract = _printHeader ? 1 : 0; - return maxRowIndex - toSubtract; + if (_printHeader) + maxRowIndex--; + + return maxRowIndex; } - private static async Task WriteColumnWidthPlaceholdersAsync(MiniExcelAsyncStreamWriter writer, ICollection props) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private static async Task WriteColumnWidthPlaceholdersAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + int count, CancellationToken cancellationToken = default) { - var placeholderPosition = await writer.FlushAsync(); - await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(props.Count)); + cancellationToken.ThrowIfCancellationRequested(); + + var placeholderPosition = await writer.FlushAsync().ConfigureAwait(false); + await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(count)).ConfigureAwait(false); 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(); - - 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); } - 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) { 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); } - private async Task PrintHeaderAsync(MiniExcelAsyncStreamWriter writer, List props, CancellationToken cancellationToken = default) + [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; - await writer.WriteAsync(WorksheetXml.StartRow(yIndex)); + const int yIndex = 1; + await writer.WriteAsync(WorksheetXml.StartRow(yIndex)).ConfigureAwait(false); + 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).ConfigureAwait(false); + } xIndex++; } - await writer.WriteAsync(WorksheetXml.EndRow); + await writer.WriteAsync(WorksheetXml.EndRow).ConfigureAwait(false); } - private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, string cellReference, string columnName) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task WriteCellAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#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); } - private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowIndex, int cellIndex, object value, ExcelColumnInfo p, ExcelWidthCollection widthCollection) + [Zomp.SyncMethodGenerator.CreateSyncVersion] + private async Task WriteCellAsync( +#if SYNC_ONLY + global::MiniExcelLibs.OpenXml.MiniExcelStreamWriter writer, +#else + MiniExcelAsyncStreamWriter writer, +#endif + int rowIndex, int cellIndex, object value, ExcelColumnInfo columnInfo, ExcelWidthCollection widthCollection) { - if (p?.CustomFormatter != null) + if (columnInfo?.CustomFormatter != null) { try { - value = p.CustomFormatter(value); + value = columnInfo.CustomFormatter(value); } catch { @@ -380,51 +450,56 @@ private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowInde } var columnReference = ExcelOpenXmlUtils.ConvertXyToCell(cellIndex, rowIndex); - var valueIsNull = value is null || value is DBNull; + var valueIsNull = value is null || + value is DBNull || + (_configuration.WriteEmptyStringAsNull && value is string vs && vs == string.Empty); if (_configuration.EnableWriteNullValueCell && valueIsNull) { - await writer.WriteAsync(WorksheetXml.EmptyCell(columnReference, GetCellXfId("2"))); + await writer.WriteAsync(WorksheetXml.EmptyCell(columnReference, GetCellXfId("2"))).ConfigureAwait(false); return; } - var tuple = GetCellValue(rowIndex, cellIndex, value, p, valueIsNull); + var tuple = GetCellValue(rowIndex, cellIndex, value, columnInfo, valueIsNull); var styleIndex = tuple.Item1; var dataType = tuple.Item2; var cellValue = tuple.Item3; - var columnType = p.ExcelColumnType; + var columnType = columnInfo.ExcelColumnType; /*Prefix and suffix blank space will lost after SaveAs #294*/ 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] 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); } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + using (var context = new SheetStyleBuildContext(_zipDictionary, _archive, _utf8WithBom, _configuration.DynamicColumns)) { ISheetStyleBuilder builder = null; @@ -437,20 +512,22 @@ 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; } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] 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); } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateDrawinRelXmlAsync(int sheetIndex, CancellationToken cancellationToken) { var drawing = GetDrawingRelationshipXml(sheetIndex); @@ -458,18 +535,20 @@ await CreateZipEntryAsync( ExcelFileNames.DrawingRels(sheetIndex), string.Empty, ExcelXml.DefaultDrawingXmlRels.Replace("{{format}}", drawing), - cancellationToken); + cancellationToken).ConfigureAwait(false); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] 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); } } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateDrawingXmlAsync(int sheetIndex, CancellationToken cancellationToken) { var drawing = GetDrawingXml(sheetIndex); @@ -477,9 +556,10 @@ await CreateZipEntryAsync( ExcelFileNames.Drawing(sheetIndex), ExcelContentTypes.Drawing, ExcelXml.DefaultDrawing.Replace("{{format}}", drawing), - cancellationToken); + cancellationToken).ConfigureAwait(false); } + [Zomp.SyncMethodGenerator.CreateSyncVersion] private async Task GenerateWorkbookXmlAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -495,58 +575,66 @@ 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 +#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 { +#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)) { @@ -554,26 +642,32 @@ 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 +#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 - 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)); } @@ -581,15 +675,18 @@ 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 +#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()) + await zipStream.WriteAsync(content, 0, content.Length, cancellationToken).ConfigureAwait(false); #endif - await zipStream.WriteAsync(content, 0, content.Length, cancellationToken); } } } \ No newline at end of file diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index 7f069f55..679f628b 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -45,98 +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); - CreateZipEntry(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString); - GenerateStylesXml(); - } - private int CreateSheetXml(object values, string sheetPath) { var entry = _archive.CreateEntry(sheetPath, CompressionLevel.Fastest); @@ -163,351 +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); - - 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 static long WriteColumnWidthPlaceholders(MiniExcelStreamWriter writer, int count) - { - var placeholderPosition = writer.Flush(); - writer.WriteWhitespace(WorksheetXml.GetColumnPlaceholderLength(count)); - 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; - 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 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(); - 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++) - { - 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 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/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/OpenXml/Styles/DefaultSheetStyleBuilder.cs b/src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs index 793f1908..dbb95e0d 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() { /* @@ -133,23 +59,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, "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); /* * @@ -160,66 +86,26 @@ 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(); - } - - 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(); + 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] protected override async Task GenerateFillAsync() { /* @@ -227,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); /* * @@ -251,127 +137,17 @@ 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(); - } - - 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(); + 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] protected override async Task GenerateBorderAsync() { /* @@ -393,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); /* * @@ -447,108 +223,43 @@ 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(); - } - - 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(); + 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] protected override async Task GenerateCellStyleXfAsync() { /* @@ -556,242 +267,73 @@ protected override async Task GenerateCellStyleXfAsync() *