C# OpenXml";“无法访问封闭流”;仅限生产

C# OpenXml";“无法访问封闭流”;仅限生产,c#,asp.net,openxml,C#,Asp.net,Openxml,生产环境:服务器2008 R2,应用程序池作为网络服务运行。 我在特定生产线的生产中遇到了这个问题,我无法理解为什么它会失败 带有堆栈跟踪的日志: 2015-02-03 11:19:29,389,DEBUG,44,Before Test1 2015-02-03 11:19:29,389,DEBUG,44,Before Test2 2015-02-03 11:19:29,451,DEBUG,44,Before Getting Row 2015-02-03 11:19:29,451,DEBUG,44

生产环境:服务器2008 R2,应用程序池作为网络服务运行。 我在特定生产线的生产中遇到了这个问题,我无法理解为什么它会失败

带有堆栈跟踪的日志:

2015-02-03 11:19:29,389,DEBUG,44,Before Test1
2015-02-03 11:19:29,389,DEBUG,44,Before Test2
2015-02-03 11:19:29,451,DEBUG,44,Before Getting Row
2015-02-03 11:19:29,451,DEBUG,44,After Getting Row
2015-02-03 11:19:29,826,DEBUG,44,Before Test1
2015-02-03 11:19:29,841,DEBUG,44,Before Test2
2015-02-03 11:19:29,841,DEBUG,44,Before Getting Row
2015-02-03 11:19:29,841,DEBUG,44,After Getting Row
2015-02-03 11:19:30,044,DEBUG,44,Before Test1
2015-02-03 11:19:30,060,DEBUG,44,Before Test2
2015-02-03 11:19:30,075,DEBUG,44,Before Getting Row
2015-02-03 11:19:30,075,DEBUG,44,After Getting Row
2015-02-03 11:19:30,138,DEBUG,44,Before Test1
2015-02-03 11:19:30,138,DEBUG,44,Before Test2
2015-02-03 11:19:30,356,DEBUG,44,Before Getting Row
2015-02-03 11:19:30,356,DEBUG,44,After Getting Row
2015-02-03 11:19:31,058,DEBUG,44,Before Test1
2015-02-03 11:19:31,074,DEBUG,44,Before Test2
2015-02-03 11:19:31,245,DEBUG,44,Before Getting Row
2015-02-03 11:19:31,245,DEBUG,44,After Getting Row
2015-02-03 11:19:31,729,DEBUG,44,Before Test1
2015-02-03 11:19:31,729,DEBUG,44,Before Test2
2015-02-03 11:19:31,745,DEBUG,44,Before Getting Row
2015-02-03 11:19:31,745,DEBUG,44,After Getting Row
2015-02-03 11:19:31,776,DEBUG,44,Before Test1
2015-02-03 11:19:31,791,DEBUG,44,Before Test2
2015-02-03 11:19:31,807,DEBUG,44,Before Getting Row
2015-02-03 11:19:31,807,DEBUG,44,After Getting Row
2015-02-03 11:19:31,869,DEBUG,44,Before Test1
2015-02-03 11:19:31,869,DEBUG,44,Before Test2
2015-02-03 11:19:31,885,DEBUG,44,Before Getting Row
2015-02-03 11:19:31,885,DEBUG,44,After Getting Row
2015-02-03 11:19:31,947,DEBUG,44,Before Test1
2015-02-03 11:19:31,947,DEBUG,44,Before Test2
2015-02-03 11:19:32,103,ERROR,44,Error exporting using template 
System.ObjectDisposedException: Can not access a closed Stream.
   at System.IO.Compression.DeflateStream.EnsureNotDisposed()
   at MS.Internal.IO.Packaging.CompressStream.Flush()
   at MS.Internal.IO.Zip.ZipIOLocalFileBlock.FlushExposedStreams()
   at MS.Internal.IO.Zip.ZipIOLocalFileBlock.UpdateReferences(Boolean closingFlag)
   at MS.Internal.IO.Zip.ZipIOBlockManager.SaveContainer(Boolean closingFlag)
   at MS.Internal.IO.Zip.ZipIOBlockManager.SaveStream(ZipIOLocalFileBlock blockRequestingFlush, Boolean closingFlag)
   at MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.Xml.XmlUtf8RawTextWriter.Close()
   at System.Xml.XmlWellFormedWriter.Close()
   at DocumentFormat.OpenXml.OpenXmlPartRootElement.SaveToPart(OpenXmlPart openXmlPart)
   at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.SavePartContents()
   at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Dispose(Boolean disposing)
   at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Dispose()
   at Metrico.DatumBase.BizLogic.ExporterBL.CreateSpreadsheetExportUsingTemplate(DataSet dataSet, String templatePath, String exportPath)
代码:


今天我读到了OpenXMLSDK(2.5及以下版本)中的一个讨厌的bug,它可能是这些异常的来源

这个错误只发生在非常特定的场景中。System.IO.Packaging对大于10MB的文件使用IsolatedStorage,但如果两个线程或可执行文件试图访问它,则会失败

System.IO.Packaging中存在一个错误,这在某些情况下会导致它在使用Open XML SDK实现开放XML功能的Web前端中使用时抛出虚假的ObjectDisposedException和NullReferenceException。此错误的要点是,如果System.IO.Packaging的内部内存使用量超过10MB的阈值,则System.IO.Packaging将使用System.IO.IsolatedStorage,如果两个可执行文件或线程同时尝试访问该存储,则会出现故障。当从具有相同强名称的多个EXE(我们将使用多个web前端应用程序)或从高性能多线程开放XML应用程序使用IsolatedStorage时,就会发生这种情况


当前,您需要从构建SDK,因为还没有正式构建。

您正在读取exportPath以处理数据吗?可能发生的一件事是,Excel(可能也适用于此处)文件有时会在同一张工作表中包含两个工作表对象。一个名称带有$前缀,另一个没有。如果您已经处理了其中一个工作表页面,那么工作表很可能已经被处理,因为名称($和no$)引用了相同的内容。每次都是同一个文件吗?@BerinLoritsch Yes导出路径是物理文件。文件的开头总是一样的(它是从一个稳定的文件中复制的,该文件是一个模板,我们正在填充内容)。我将添加一个检查,以查看是否有多个具有相同名称的工作表,但如果是这样,在开发过程中不会发生这种情况吗?不总是这样。它可能是变更管理的产物,而不是正确的清理。记录日志时,输出工作表的名称可能会很有用,这样您就可以准确地知道自己在模板中的位置。@BerinLoritsch我刚刚将工作表选择更改为SingleOrDefault,并得到了相同的错误。我还更改了日志记录以输出工作表名称,但它还没有使用该名称制作工作表。这有帮助吗-
try
{
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(exportPath, true))
    {
        WorkbookPart workbookPart = document.WorkbookPart;

        // Iterate through the DataTables, and populate the existing worksheets with the same names
        for (int i = 1; i < dataSet.Tables.Count; i++)
        {
            // Grab the DataTable/Worksheet name from the first DataTable (like a Table of Contents)
            var worksheetName = dataSet.Tables[0].Rows[i - 1].Field<string>("FriendlyName");

            // Get the worksheet that has the same name
            Sheet theSheet = workbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name == worksheetName);

            // Only attempt to process the sheet if it was found in the template
            if (theSheet != null)
            {
                // Get the worksheet to read from
                var worksheetPart = (WorksheetPart) workbookPart.GetPartById(theSheet.Id);
                string originalSheetID = workbookPart.GetIdOfPart(worksheetPart);

                // Make a copy of the worksheet to write to
                var replacementPart = workbookPart.AddNewPart<WorksheetPart>();
                string replacementPartID = workbookPart.GetIdOfPart(replacementPart);

                // Create the reader for the original and the writer for the replacement
                using (var reader = OpenXmlReader.Create(worksheetPart))
                {
                    using (var writer = OpenXmlWriter.Create(replacementPart))
                    {
                        // Get the cell formats for the first non-header row
                        WorkbookStylesPart stylesPart = workbookPart.GetPartsOfType<WorkbookStylesPart>().First();
                        Logger.Log(LogLevel.Debug, "Before Test1");
                        var test1 = worksheetPart;
                        Logger.Log(LogLevel.Debug, "Before Test2");
                        var test2 = worksheetPart.Worksheet;
                        Logger.Log(LogLevel.Debug, "Before Getting Row");
                        Row firstContentRow = worksheetPart.Worksheet.Descendants<Row>().FirstOrDefault(r => r.RowIndex == 2);
                        Logger.Log(LogLevel.Debug, "After Getting Row");
                        Dictionary<string, uint> columnFormats = GetCellFormats(firstContentRow);
                        // Create a DateTime cell format style
                        var dateFormat = new CellFormat
                        {
                            NumberFormatId = UInt32Value.FromUInt32(22),
                            ApplyNumberFormat = BooleanValue.FromBoolean(true)
                        };
                        stylesPart.Stylesheet.CellFormats.Append(dateFormat);
                        UInt32Value dateStyleIndex = stylesPart.Stylesheet.CellFormats.Count;
                        stylesPart.Stylesheet.CellFormats.Count++;

                        // Read from the template worksheet and write to the new worksheet
                        while (reader.Read())
                        {
                            // We only care about altering the contents of the SheetData element
                            if (reader.ElementType == typeof (SheetData))
                            {
                                if (reader.IsEndElement)
                                {
                                    continue;
                                }

                                // Write the start of the SheetData element
                                writer.WriteStartElement(new SheetData());

                                // Add column names to the first Excel row
                                var headerRow = new Row();
                                foreach (DataColumn column in dataSet.Tables[i].Columns)
                                {
                                    var headerCell = CreateTextCell(
                                        dataSet.Tables[i].Columns.IndexOf(column) + 1, 1, column.ColumnName, null);
                                    headerRow.Append(headerCell);
                                }
                                // Write the head row element
                                writer.WriteElement(headerRow);

                                // Loop through each DataRow and populate the corresponding Excel row
                                for (int j = 0; j < dataSet.Tables[i].Rows.Count; j++)
                                {
                                    var contentRow = dataSet.Tables[i].Rows[j];

                                    Row row = CreateContentRow(contentRow, j + 2, columnFormats, dateStyleIndex);

                                    // Write the row element
                                    writer.WriteElement(row);

                                }

                                // Write the end of the SheetData element
                                writer.WriteEndElement();
                            }
                            else
                            {
                                // Automatically copy over all other elements
                                if (reader.IsStartElement)
                                {
                                    writer.WriteStartElement(reader);
                                }
                                else if (reader.IsEndElement)
                                {
                                    writer.WriteEndElement();
                                }
                            }
                        }
                    }
                }

                // Point the workbook to the new sheet and delete the old one
                Sheet sheet = workbookPart.Workbook.Descendants<Sheet>().First(s => s.Id.Value.Equals(originalSheetID));
                sheet.Id.Value = replacementPartID;
                workbookPart.DeletePart(worksheetPart);
            }
        }

        //This section will remove data from sheets that have not been populated, leaving the header row intact
        List<string> emptyTasks = new List<string>
        {
            "task",
        };

        var currentTasks =
            dataSet.Tables[0].AsEnumerable()
                .Select(x => x.Field<string>("FriendlyName").ToString(CultureInfo.InvariantCulture))
                .ToList();

        foreach (string task in currentTasks.Where(emptyTasks.Contains))
        {
            emptyTasks.Remove(task);
        }

        foreach (string task in emptyTasks)
        {
            Sheet theSheet = workbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name == task);
            if (theSheet != null)
            {
                WorksheetPart worksheetPart = (WorksheetPart) workbookPart.GetPartById(theSheet.Id);

                SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();

                sheetData.Elements<Row>().Where(r => r.RowIndex > 1).ToList().ForEach(x => x.Remove());
                theSheet.Elements<Row>().ToList().ForEach(x => x.Remove());

                worksheetPart.Worksheet.Save();
            }
        }

        workbookPart.Workbook.CalculationProperties.ForceFullCalculation = true;
        workbookPart.Workbook.CalculationProperties.FullCalculationOnLoad = true;
    }
}
catch (Exception ex)
{
    Logger.Log(LogLevel.Error, "Error exporting using template ", ex);
    throw;
}
2015-02-04 09:45:23,577,ERROR,6,Error exporting using template 
System.IO.IsolatedStorage.IsolatedStorageException: Unable to create mutex. (Exception from HRESULT: 0x80131464)
   at System.IO.IsolatedStorage.IsolatedStorageFile.Open(String infoFile, String syncName)
   at System.IO.IsolatedStorage.IsolatedStorageFile.Lock(Boolean& locked)
   at System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, IsolatedStorageFile isf)
   at System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, IsolatedStorageFile isf)
   at MS.Internal.IO.Packaging.PackagingUtilities.SafeIsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, ReliableIsolatedStorageFileFolder folder)
   at MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32 retryCount, String& fileName)
   at MS.Internal.IO.Packaging.SparseMemoryStream.EnsureIsolatedStoreStream()
   at MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()
   at MS.Internal.IO.Packaging.DeflateEmulationTransform.Decompress(Stream source, Stream sink)
   at MS.Internal.IO.Packaging.CompressEmulationStream..ctor(Stream baseStream, Stream tempStream, Int64 position, IDeflateTransform transformer)
   at MS.Internal.IO.Packaging.CompressStream.ChangeMode(Mode newMode)
   at MS.Internal.IO.Packaging.CompressStream.Seek(Int64 offset, SeekOrigin origin)
   at MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Xml.XmlTextReaderImpl.InitStreamInput(Uri baseUri, String baseUriStr, Stream stream, Byte[] bytes, Int32 byteCount, Encoding encoding)
   at System.Xml.XmlTextReaderImpl.FinishInitStream()
   at System.Xml.XmlReaderSettings.CreateReader(Stream input, Uri baseUri, String baseUriString, XmlParserContext inputContext)
   at DocumentFormat.OpenXml.OpenXmlPartRootElement.LoadFromPart(OpenXmlPart openXmlPart, Stream partStream)
   at DocumentFormat.OpenXml.Packaging.OpenXmlPart.LoadDomTree[T]()
   at DocumentFormat.OpenXml.Packaging.WorksheetPart.get_Worksheet()
   at Metrico.DatumBase.BizLogic.ExporterBL.CreateSpreadsheetExportUsingTemplate(DataSet dataSet, String templatePath, String exportPath)