dotnet / Open-XML-SDK

Open XML SDK by Microsoft

Home Page:https://www.nuget.org/packages/DocumentFormat.OpenXml/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MissingMethodException at OfficeOpenXml with latest RecyclableMemoryStream (3.0.0)

birbilis opened this issue · comments

Describe the bug
I started getting an exception at latest OfficeOpenXml (using latest version from NuGet) with the breaking changes that RecycleableMemoryStream (3.0.0 version from NuGet) introduced

[System.MissingMethodException]
Method not found: 'System.IO.MemoryStream Microsoft.IO.RecyclableMemoryStreamManager.GetStream()'.
at OfficeOpenXml.Utils.RecyclableMemory.GetStream()
at OfficeOpenXml.ExcelPackage.ConstructNewFile(String password)

I'm not aware why those breaking changes had to be introduced, they're mentioned here:
https://github.com/microsoft/Microsoft.IO.RecyclableMemoryStream/blob/master/CHANGES.md#version-300

I'd expect Microsoft to not break their own NuGet packages

My code is the following:

        /// <summary>
        /// Convert DataTable to Excel file in byte array form
        /// </summary>
        /// <param name="dt">DataTable</param>
        /// <returns></returns>
        public static byte[] DataTableToExcelByteArray(DataTable dt)
        {
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial; //Educational Institution, Public Research Organization and Government Institutions use permitted (among others) via https://polyformproject.org/licenses/noncommercial/1.0.0/
            using (ExcelPackage pck = new ExcelPackage())
            {
                //Create the worksheet  
                ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Sheet1"); //set Worksheet Name  
                //Load the datatable into the sheet, starting from cell A1. Print the column names on row 1  
                ws.Cells["A1"].LoadFromDataTable(dt, true);

                ws.DefaultColWidth = 40;

                //Format the header for columns  
                using (ExcelRange header = ws.Cells[1, 1, 1, dt.Columns.Count])
                {
                    header.Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
                    header.Style.Font.Bold = true;
                    header.Style.Fill.PatternType = ExcelFillStyle.Solid;
                    header.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightSteelBlue);
                    header.Style.Font.Color.SetColor(System.Drawing.Color.Black);
                    header.Style.ShrinkToFit = false;
                }

                //prepare the range for the rows  
                //string rowsCellRange = "A2:A" + dt.Rows.Count.ToString();

                //Format the rows  
                using (ExcelRange rng = ws.Cells[2, 1, (dt.Rows.Count + 1), dt.Columns.Count])
                {
                    rng.Style.WrapText = true;
                    rng.Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
                    rng.Style.Fill.PatternType = ExcelFillStyle.None; //Set Pattern for the background to Solid  
                    //only if the pattern type is defined 
                    //rng.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.White);
                    rng.Style.Font.Color.SetColor(System.Drawing.Color.Black);
                }

                //Read the Excel file in a byte array  
                return pck.GetAsByteArray();
            }
        }

it fails at
using (ExcelPackage pck = new ExcelPackage())

if I rollback the RecyclableMemoryStream NuGet package to its previous version (2.3.2, before the breaking changes introduction) from the latest 3.0.0 it works again

commented

Woops, thought I was commenting on the RMS project. I'll delete, and move my comments over there.

@birbilis Where is this ExcelPackage coming from? It's neither in this project nor in RecyclableMemoryStream

As @benmwatson mentioned in microsoft/Microsoft.IO.RecyclableMemoryStream#324, we did a major version change, and so consuming libraries will need to be updated to work with it. It's mostly a recompilation requirement, but a few code changes are required. See docs for detailed list and actions to take

There's no action here for us, but feel free to tag me in whatever repo owns ExcelPackage and I can help provide guidance for migration.

Where is this ExcelPackage coming from? It's neither in this project nor in RecyclableMemoryStream

Seems that even though its under OfficeOpenXml namespace it's coming from EPPlus NuGet package
FYI @EPPlusSoftware (https://github.com/EPPlusSoftware/EPPlus)

#region Assembly EPPlus, Version=7.0.5.0, Culture=neutral, PublicKeyToken=ea159fdaa78159a1
// C:\Users\user\Desktop\Promithiesv2\packages\EPPlus.7.0.5\lib\net462\EPPlus.dll
#endregion

using OfficeOpenXml.Compatibility;
using OfficeOpenXml.Configuration;
using OfficeOpenXml.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace OfficeOpenXml
{
    //
    // Summary:
    //     Represents an Excel XLSX file package. This is the top-level object to access
    //     all parts of the document.
    //
    // Remarks:
    //     FileInfo newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx");
    //     if (newFile.Exists)
    //     {
    //     newFile.Delete();  // ensures we create a new workbook
    //     newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx");
    //     }
    //     using (ExcelPackage package = new ExcelPackage(newFile))
    //     {
    //     // add a new worksheet to the empty workbook
    //     ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Inventory");
    //     //Add the headers
    //     worksheet.Cells[1, 1].Value = "ID";
    //     worksheet.Cells[1, 2].Value = "Product";
    //     worksheet.Cells[1, 3].Value = "Quantity";
    //     worksheet.Cells[1, 4].Value = "Price";
    //     worksheet.Cells[1, 5].Value = "Value";
    //     //Add some items...
    //     worksheet.Cells["A2"].Value = "12001";
    //     worksheet.Cells["B2"].Value = "Nails";
    //     worksheet.Cells["C2"].Value = 37;
    //     worksheet.Cells["D2"].Value = 3.99;
    //     worksheet.Cells["A3"].Value = "12002";
    //     worksheet.Cells["B3"].Value = "Hammer";
    //     worksheet.Cells["C3"].Value = 5;
    //     worksheet.Cells["D3"].Value = 12.10;
    //     worksheet.Cells["A4"].Value = "12003";
    //     worksheet.Cells["B4"].Value = "Saw";
    //     worksheet.Cells["C4"].Value = 12;
    //     worksheet.Cells["D4"].Value = 15.37;
    //     //Add a formula for the value-column
    //     worksheet.Cells["E2:E4"].Formula = "C2*D2";
    //     //Ok now format the values;
    //     using (var range = worksheet.Cells[1, 1, 1, 5])
    //     {
    //     range.Style.Font.Bold = true;
    //     range.Style.Fill.PatternType = ExcelFillStyle.Solid;
    //     range.Style.Fill.BackgroundColor.SetColor(Color.DarkBlue);
    //     range.Style.Font.Color.SetColor(Color.White);
    //     }
    //     worksheet.Cells["A5:E5"].Style.Border.Top.Style = ExcelBorderStyle.Thin;
    //     worksheet.Cells["A5:E5"].Style.Font.Bold = true;
    //     worksheet.Cells[5, 3, 5, 5].Formula = string.Format("SUBTOTAL(9,{0})", new ExcelAddress(2,3,4,3).Address);
    //     worksheet.Cells["C2:C5"].Style.Numberformat.Format = "#,##0";
    //     worksheet.Cells["D2:E5"].Style.Numberformat.Format = "#,##0.00";
    //     //Create an autofilter for the range
    //     worksheet.Cells["A1:E4"].AutoFilter = true;
    //     worksheet.Cells["A1:E5"].AutoFitColumns(0);
    //     // lets set the header text
    //     worksheet.HeaderFooter.oddHeader.CenteredText = "&24&U&\"Arial,Regular Bold\"
    //     Inventory";
    //     // add the page number to the footer plus the total number of pages
    //     worksheet.HeaderFooter.oddFooter.RightAlignedText =
    //     string.Format("Page {0} of {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages);
    //     // add the sheet name to the footer
    //     worksheet.HeaderFooter.oddFooter.CenteredText = ExcelHeaderFooter.SheetName;
    //     // add the file path to the footer
    //     worksheet.HeaderFooter.oddFooter.LeftAlignedText = ExcelHeaderFooter.FilePath
    //     + ExcelHeaderFooter.FileName;
    //     worksheet.PrinterSettings.RepeatRows = worksheet.Cells["1:2"];
    //     worksheet.PrinterSettings.RepeatColumns = worksheet.Cells["A:G"];
    //     // Change the sheet view to show it in page layout mode
    //     worksheet.View.PageLayoutView = true;
    //     // set some document properties
    //     package.Workbook.Properties.Title = "Invertory";
    //     package.Workbook.Properties.Author = "Jan Källman";
    //     package.Workbook.Properties.Comments = "This sample demonstrates how to create
    //     an Excel 2007 workbook using EPPlus";
    //     // set some extended property values
    //     package.Workbook.Properties.Company = "AdventureWorks Inc.";
    //     // set some custom property values
    //     package.Workbook.Properties.SetCustomPropertyValue("Checked by", "Jan Källman");
    //     package.Workbook.Properties.SetCustomPropertyValue("AssemblyName", "EPPlus");
    //     // save our new workbook and we are done!
    //     package.Save();
    //     }
    //     return newFile.FullName;
    //     More samples can be found at https://github.com/EPPlusSoftware/EPPlus/
    public sealed class ExcelPackage : IDisposable
    {
        //
        // Summary:
        //     Maximum number of columns in a worksheet (16384).
        public const int MaxColumns = 16384;
        //
        // Summary:
        //     Maximum number of rows in a worksheet (1048576).
        public const int MaxRows = 1048576;
...

As I noted above, issue proved to have been with EPPlus (was confused since it is using OfficeOpenXml namespace for its ExcelPackage class). They seem to have now fixed it with latest EPPlus NuGet package release (7.0.8)