I'm using this simple pattern to create a docx file in an ASP.NET app:
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();
I have to say, the data I'm working on, is about 100,000 records from DB.
In local, it works just fine; in production server (win 2012 R2), it works fine for small files; but in large files (when there is too many records to write to file) I get this error:
Unable to create mutex. (Exception from HRESULT: 0x80131464)
And here is the stack trace:
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()
The question is: While I'm writing the file to my own App_Data
folder, why it's going to IsolatedStorage
? How can I prevent that?
In the stack trace you can find 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. In other words it is by design.
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
The author of EPPlus library had the similar problem and it seems to me that the solution was to use non-Microsoft packaging library.
I don't know openxml-sdk but maybe it is possible to replace a default Microsoft packaging solution with something else.
User contributions licensed under CC BY-SA 3.0