Using WordprocessingDocument error: Unable to create mutex

Using WordprocessingDocument error: Unable to create mutex

我正在使用这个简单的模式在 ASP.NET 应用程序中创建一个 docx 文件:

var outputFileName = "creating some file name here...";
var outputFile = string.Format("~/App_Data/files/{0}.docx", outputFileName);

// creating a file stream to write to
var outputStream = new FileStream(HttpContext.Current.Server.MapPath(outputFile), FileMode.OpenOrCreate);

// creating the default template
using (var sr = new StreamReader(HttpContext.Current.Server.MapPath("~/some-template.docx"), Encoding.UTF8)) {
    var l = (int)sr.BaseStream.Length;
    var buffer = new byte[l];
    sr.BaseStream.Read(buffer, 0, l);
    outputStream.Write(buffer, 0, l);
}

// creating the document parts
using (WordprocessingDocument docx = WordprocessingDocument.Open(outputStream, true)) {
    // adding parts here...

    // adding a large amount of data in an iterator 
    foreach(var item in someList) {
        // adding some parts...
        outputStream.Flush();
    }

    docx.Close();
}

outputStream.Flush();
outputStream.Close();
outputStream.Dispose();

我不得不说,我正在处理的数据是来自数据库的大约 100,000 条记录。

在本地,它工作得很好;在生产服务器(win 2012 R2)中,它适用于小文件;但是在大文件中(当有太多记录要写入文件时)我得到这个错误:

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 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.SwitchModeIfNecessary() at MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) at MS.Internal.IO.Packaging.CompressEmulationStream.Write(Byte[] buffer, Int32 offset, Int32 count) at MS.Internal.IO.Packaging.CompressStream.Write(Byte[] buffer, Int32 offset, Int32 count) at MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[] buffer, Int32 offset, Int32 count) at MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[] buffer, Int32 offset, Int32 count) at System.Xml.XmlUtf8RawTextWriter.FlushBuffer() at System.Xml.XmlUtf8RawTextWriter.RawText(Char* pSrcBegin, Char* pSrcEnd) at System.Xml.XmlUtf8RawTextWriter.RawText(String s) at System.Xml.XmlUtf8RawTextWriter.WriteStartAttribute(String prefix, String localName, String ns) at System.Xml.XmlWellFormedWriter.WriteStartAttribute(String prefix, String localName, String namespaceName) at DocumentFormat.OpenXml.OpenXmlElement.WriteAttributesTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(XmlWriter w) at DocumentFormat.OpenXml.OpenXmlPartRootElement.WriteTo(XmlWriter xmlWriter) at DocumentFormat.OpenXml.OpenXmlPartRootElement.SaveToPart(OpenXmlPart openXmlPart) at DocumentFormat.OpenXml.OpenXmlPartRootElement.Save() at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.SavePartContents() at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Dispose(Boolean disposing) at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Dispose() at MyClass.GetDocx()

问题是: 当我将文件写入我自己的 App_Data 文件夹时,为什么要写入 IsolatedStorage?我怎样才能防止这种情况发生?

在堆栈跟踪中,您可以找到 SparseMemoryStream class. This class under the hood uses either Memory Stream or Isolated Storage. It depends on 2 parameters called Low Water Mark and High Water Mark. If memory consumption is > than High Water Mark then Isolated Storage is used. As you observed it becomes a problem in the case of server side applications running on IIS. Unfortunately, the problem is that values of these parameters are hard coded in the CompressStream class。换句话说,这是设计使然。

 private const long _lowWaterMark = 0x19000; // we definately would like to keep everythuing under 100 KB in memory  
 private const long _highWaterMark = 0xA00000; // we would like to keep everything over 10 MB on disk

EPPlus 库的作者有类似的 problem,在我看来,解决方案是使用非 Microsoft 打包库。

我不知道 openxml-sdk,但也许可以用其他东西替换默认的 Microsoft 打包解决方案。