为什么 EPPlus 在访问工作簿时抛出空引用异常

Why is EPPlus Throwing Null Reference Exception on Accessing Workbook

我正在使用 C# .NET Core 2.2 进行编码。我试图在我的代码中用 EPPlusCore 替换 Excel Interop,以提高可靠性和可移植性。我有一系列使用 EPPlus 打开的发票,但其中一些在访问 Excel 包的工作簿 属性 时抛出 "Null Reference" 异常。

这只发生在 运行未调试代码的情况下。调试时,如果我将鼠标悬停在 ExcelPackage 项目上,它会刷新对工作簿的引用,并且我能够 运行 其余代码。

public object[,] GetExcelDataEpplus(string filePath, int index,
            bool sheetByName = false, string name = null, string password = null)
        {
            var remoteFileInfo = new FileInfo(filePath);

            if (!remoteFileInfo.Exists)
            {
                throw new Exception("File does not exist: " + filePath);
            }

            var currentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "temp-excel");

            if (!Directory.Exists(currentPath))
            {
                Directory.CreateDirectory(currentPath);
            }

            var localFileInfo = new FileInfo(Path.Combine(currentPath, remoteFileInfo.Name));

            if (!localFileInfo.Exists)
            {
                File.Copy(filePath, localFileInfo.FullName);
            }

            object[,] values = null;
            try
            {
                if (!File.Exists(localFileInfo.FullName))
                {
                    _logger.LogInformation(DbLog, "Cannot find file : " + localFileInfo.FullName);
                    return null;
                }
                else
                {
                    _logger.LogInformation(DbLog, "Found file : " + localFileInfo.FullName);
                }

                _logger.LogInformation(DbLog, "Initializing EPPlus...");

                using (var package = string.IsNullOrEmpty(password)
                    ? new ExcelPackage(localFileInfo)
                    : new ExcelPackage(localFileInfo, password))
                {

                    _logger.LogInformation(DbLog, "Opening Workbook...");

                    //todo Error Thrown Here

                    try
                    {
                        package.Workbook.FormulaParserManager.LoadFunctionModule(new ImporterFunctionModule());
                    }
                    catch (Exception e)
                    {
                        _logger.LogWarning(DbLog, e, $"Could not load workbook : Loading file again...");

                        try
                        {
                            System.Threading.Thread.Sleep(1000);
                            package.Workbook.FormulaParserManager.LoadFunctionModule(new ImporterFunctionModule());
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(DbLog, ex, "Could not load workbook");
                            throw;
                        }
                    }

                    var workbook = package.Workbook;

                    _logger.LogInformation(DbLog, $"Calculating formulas...");

                    workbook.Calculate();

                    _logger.LogInformation(DbLog, "Finding Worksheet...");

                    var worksheet = sheetByName ? workbook.Worksheets.FirstOrDefault(x => x.Name == name) : workbook.Worksheets[index];

                    if (worksheet == null)
                    {
                        throw new Exception($"Could not find worksheet : {name}");
                    }

                    _logger.LogInformation(DbLog, $"Reading from worksheet : {worksheet.Name}...");


                    var start = worksheet.Dimension.Start;
                    var end = worksheet.Dimension.End;

                    values = worksheet.Cells[start.Row, start.Column, end.Row, end.Column].ToMultiDimensionalArray();
                }
            }
            catch (Exception e)
            {
                _logger.LogError(DbLog, e, $"GetExcelInvoiceDataEpplus from {filePath} ({localFileInfo.FullName})"); //todo propogate error
            }
            finally
            {
                File.Delete(localFileInfo.FullName);
            }

            var rowCount = values?.GetLength(0) ?? 0;
            _logger.LogInformation(DbLog, $"EPPLus found {rowCount} rows in the spreadsheet");
            return values;
        }

在大多数文件上,这都能正常工作,并且我从指定的工作表选项卡中获得了值的多维数组。但是,在某些文件上,它不起作用,我不知道为什么。

我能找到的最接近的类似问题是:https://github.com/JanKallman/EPPlus/issues/416

但如果这是准确的,我怎么知道哪些工作表名称有错误引用而不先访问工作簿?

我找到了解决方案。 excel 个有问题的文件是大于平均水平的文件。

解决办法就是多等他们一段时间。


try
{
    package.Workbook.FormulaParserManager.LoadFunctionModule(new ImporterFunctionModule());
}
catch (Exception e)
{
    for (var i=1; i < 6; i++)
    {
        _logger.LogWarning(DbLog, e, $"Could not load workbook : Loading file again (Attempt #{i})...");
        try
        {
            System.Threading.Thread.Sleep(2000);
            package.Workbook.FormulaParserManager.LoadFunctionModule(new ImporterFunctionModule());
            break;
        }
        catch (Exception ex)
        {
            if (i < 5) continue;

            _logger.LogError(DbLog, ex, "Could not load workbook after 5 attempts");
            throw;
        }
    }
}