From 2537ed865ae1a8ee169c7c765ea2bd098724b22f Mon Sep 17 00:00:00 2001 From: Michele Bastione Date: Mon, 27 Apr 2026 21:27:57 +0200 Subject: [PATCH] Added check to OpenXmlValueExtractor to exclude indexers from property mapping --- .../Templates/OpenXmlValueExtractor.cs | 2 ++ .../Utils/CalcChainHelper.cs | 21 ++++++++------ .../MiniExcelIssueAsyncTests.cs | 28 +++++++++++++++++++ .../MiniExcelIssueTests.cs | 28 +++++++++++++++++++ 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/MiniExcel.OpenXml/Templates/OpenXmlValueExtractor.cs b/src/MiniExcel.OpenXml/Templates/OpenXmlValueExtractor.cs index 421762a2..39cc2525 100644 --- a/src/MiniExcel.OpenXml/Templates/OpenXmlValueExtractor.cs +++ b/src/MiniExcel.OpenXml/Templates/OpenXmlValueExtractor.cs @@ -20,8 +20,10 @@ public class OpenXmlValueExtractor : IInputValueExtractor { var type = valueObject.GetType(); + //todo: consider throwing an exception if a property has indexer instead of silently ignoring it var propertyValues = type .GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(property => property.CanRead && property.GetIndexParameters().Length == 0) .Select(property => new { property.Name, Value = property.GetValue(valueObject) }); var fieldValues = type diff --git a/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs b/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs index 42d93e11..f58fadfc 100644 --- a/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs +++ b/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs @@ -2,19 +2,18 @@ internal static partial class CalcChainHelper { - // The calcChain.xml file in an Excel file (in the xl folder) is an XML file that stores the calculation chain for the workbook. // The calculation chain specifies the order in which cells should be recalculated in order to update all formulas in the workbook correctly. // It should include a series of elements, each of which represents a cell in the workbook that contains a formula. // Each element should have a r attribute that specifies the cell's address (e.g., "A1" or "B2"). // The element should also have a i attribute that specifies the index of the formula in the formulas collection (in the workbook's sheet data file). // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.calculationchain?view=openxml-2.8.1 - public static string GetCalcChainContent( List cellRefs, int sheetIndex ) { - + public static string GetCalcChainContent(List cellRefs, int sheetIndex ) + { var calcChainContent = new StringBuilder(); foreach (var cr in cellRefs) { - calcChainContent.Append($"""""" ); + calcChainContent.Append($""""""); } return calcChainContent.ToString(); @@ -23,11 +22,15 @@ public static string GetCalcChainContent( List cellRefs, int sheetIndex [CreateSyncVersion] public static async Task GenerateCalcChainSheetAsync(Stream calcChainStream, string calcChainContent, CancellationToken cancellationToken = default) { + var content = $"{calcChainContent}"; + +#if NET8_0_OR_GREATER + var writer = new StreamWriter(calcChainStream, Encoding.UTF8); + await using var disposableWriter = writer.ConfigureAwait(false); + await writer.WriteAsync(content.AsMemory(), cancellationToken).ConfigureAwait(false); + #else using var writer = new StreamWriter(calcChainStream, Encoding.UTF8); - await writer.WriteAsync($"""{calcChainContent}""" -#if NET7_0_OR_GREATER - .AsMemory(), cancellationToken -#endif - ).ConfigureAwait(false); + await writer.WriteAsync(content).ConfigureAwait(false); + #endif } } diff --git a/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueAsyncTests.cs b/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueAsyncTests.cs index ec9f7891..f1f2862f 100644 --- a/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueAsyncTests.cs +++ b/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueAsyncTests.cs @@ -1476,4 +1476,32 @@ private class Issue138ExcelRow public double? 波段 { get; set; } public double? 當沖 { get; set; } } + + [Fact] + public async Task TestIssue951() + { + var templatePath = PathHelper.GetFile("xlsx/TestTemplateEasyFill.xlsx"); + using var path = AutoDeletingPath.Create(); + + var value = new Issue951 + { + Name = "Jack", + CreateDate = new DateTime(2021, 01, 01), + VIP = true, + Points = 123 + }; + + // must not throw + await _excelTemplater.FillTemplateAsync(path.ToString(), templatePath, value); + } + + class Issue951 + { + public string? Name { get; set; } + public DateTime CreateDate { get; set; } + public bool VIP { get; set; } + public double Points { get; set; } + + public object this[string test] => new(); + } } \ No newline at end of file diff --git a/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueTests.cs b/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueTests.cs index f79fb95c..4193bac7 100644 --- a/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueTests.cs +++ b/tests/MiniExcel.OpenXml.Tests/MiniExcelIssueTests.cs @@ -3827,4 +3827,32 @@ public void TestIssue915() Assert.Equal(7.4, result[1].Altitude); Assert.Equal(8.6, result[2].Altitude); } + + [Fact] + public void TestIssue951() + { + var templatePath = PathHelper.GetFile("xlsx/TestTemplateEasyFill.xlsx"); + using var path = AutoDeletingPath.Create(); + + var value = new Issue951 + { + Name = "Jack", + CreateDate = new DateTime(2021, 01, 01), + VIP = true, + Points = 123 + }; + + // must not throw + _excelTemplater.FillTemplate(path.ToString(), templatePath, value); + } + + class Issue951 + { + public string? Name { get; set; } + public DateTime CreateDate { get; set; } + public bool VIP { get; set; } + public double Points { get; set; } + + public object this[string test] => new(); + } }