-
Notifications
You must be signed in to change notification settings - Fork 557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open XML SDK System.IO.IOException: "Entries cannot be opened multiple times in Update mode" during disposal #1801
Comments
Hi @Yaroslav-Andrieiev-Net To be able to troubleshoot your issue could you please provide the following so I can test it on my site and check for errors: this.PrefixResolver(prefix, namespaceManager); that I am not able to resolve. Also please hardcode all the constants or provide constants class EdocsConversionConstant Possibly issue maybe somewhere in the extension methods as you are opening streams there but without working example I am not able to tell for sure. Thanks |
Hi @mkaszewiak public interface IFileLoggerInfo
{
public int FileId { get; set; }
public string FileName { get; set; }
}
public interface IOpenXMLCorrector : ISingletonDependency
{
void FixSharePointFile(MemoryStream stream, IFileLoggerInfo printDocDocument, string extension);
}
public class OpenXMLCorrector : IOpenXMLCorrector
{
private static readonly ILog Log = LogManager.GetLogger(CustomLoggerDefinition.Background);
public void FixSharePointFile(MemoryStream stream, IFileLoggerInfo fileLoggerInfo, string extension)
{
WordprocessingDocument wordDoc = null;
try
{
try
{
// TODO: Remove RelationshipErrorHandlerFactory after OpenXml SDK upgrade to 3.0.1+
wordDoc = WordprocessingDocument.Open(stream, true, new OpenSettings
{
RelationshipErrorHandlerFactory = RelationshipErrorHandler.CreateRewriterFactory((_, _, _) => "about:blank")
});
}
catch (InvalidOperationException e)
{
Log.Error($"OpenXML file open exception. CaseFileId: {fileLoggerInfo.FileId}, file name: {fileLoggerInfo.FileName}", e);
throw new BusinessException(LocalizedString.Get(Messages.OpenXMLFileOpenError));
}
var partsAndBindings = wordDoc.MainDocumentPart.GetXMLPartsAndBindings();
var doc = wordDoc.MainDocumentPart.GetXmlDocByNamespace(EdocsConversionConstants.Myns);
if (doc is { ChildNodes.Count: > 0 })
{
var namespaceManager = new XmlNamespaceManager(doc.NameTable);
var xDoc = doc.ToXDocument();
foreach (var part in partsAndBindings)
{
foreach (var binding in part.Item2)
{
var xpath = binding.Attribute(EdocsConversionConstants.W + "xpath")?.Value;
var prefix = binding.Attribute(EdocsConversionConstants.W + "prefixMappings")?.Value;
this.PrefixResolver(prefix, namespaceManager);
if (xpath.IsNotEmpty())
{
var sdtPrCollection = binding.Parent?.Parent?.Descendants(EdocsConversionConstants.W + "sdtPr");
var rCollection = binding.Parent?.Parent?.Descendants(EdocsConversionConstants.W + "r");
if (sdtPrCollection.Any() && rCollection.Any())
{
var r = rCollection?.GetFirstAndRemoveOthers();
var sdtPr = sdtPrCollection?.First();
var rprCollection = sdtPr?.Descendants(EdocsConversionConstants.W + "rPr");
if (rprCollection.Any())
{
var rPr = rprCollection?.First();
var rPrRCollection = r?.Descendants(EdocsConversionConstants.W + "rPr");
if (rPrRCollection.Any())
{
rPrRCollection.First()?.ReplaceWith(rPr);
}
}
var t = r?.Descendants(EdocsConversionConstants.W + "t")?.GetFirstAndRemoveOthers();
r?.Descendants(EdocsConversionConstants.W + "tab")?.GetFirstAndRemoveOthers()?.Remove();
r?.Descendants(EdocsConversionConstants.W + "br")?.GetFirstAndRemoveOthers()?.Remove();
if (t != null)
{
var v = xDoc?.XPathSelectElement(xpath, namespaceManager)?.Value;
if (v.IsEmpty())
{
t.Remove();
}
}
}
}
}
part.Item1.PutXDocument();
}
}
wordDoc?.Dispose();
stream?.Seek(0, SeekOrigin.Begin);
}
finally
{
wordDoc?.Dispose();
}
}
private void PrefixResolver(string prefix, XmlNamespaceManager namespaceManager)
{
var xPrefixSepColl = prefix?.Trim()?.Split(
new[]
{
"xmlns:"
},
StringSplitOptions.RemoveEmptyEntries);
if (xPrefixSepColl == null || xPrefixSepColl.Length == 0)
{
return;
}
foreach (var xPrefixSep in xPrefixSepColl)
{
var s = new string(xPrefixSep.TakeWhile(x => x != '=').ToArray());
if (!namespaceManager.HasNamespace(s))
{
var v = xPrefixSep.Trim().Replace(s + "=", string.Empty);
if (v.StartsWith("\'"))
{
v = v.Remove(0, 1);
}
if (v.EndsWith("\'"))
{
v = v.Remove(v.Length - 1, 1);
}
namespaceManager.AddNamespace(s, v);
}
}
}
} Class with extenstion methods public static class XmlDocumentExtensions
{
private static readonly XNamespace w = @"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
public static string GetDataValue(this XElement dataElement, string existsValue)
{
var formatValue = dataElement.GetExementAttributeValue("dateFormat");
var cultureValue = dataElement.GetExementAttributeValue("lid");
var date = Convert.ToDateTime(existsValue);
return date.ToString(formatValue, new CultureInfo(cultureValue));
}
public static XDocument ToXDocument(this XmlDocument document)
{
return document.ToXDocument(LoadOptions.None);
}
public static XElement GetFirstAndRemoveOthers(this IEnumerable<XElement> collection)
{
if (collection.Any())
{
var length = collection.Count();
if (length > 1)
{
for (var i = length - 1; i > 0; i--)
{
collection.ElementAt(i).Remove();
}
}
return collection.FirstOrDefault();
}
return null;
}
public static XDocument ToXDocument(this XmlDocument document, LoadOptions options)
{
using (var reader = new XmlNodeReader(document))
{
return XDocument.Load(reader, options);
}
}
public static XDocument GetXDocument(this OpenXmlPart part)
{
var xdoc = part.Annotation<XDocument>();
if (xdoc != null)
return xdoc;
using (var sr = new StreamReader(part.GetStream()))
using (var xr = XmlReader.Create(sr))
xdoc = XDocument.Load(xr);
part.AddAnnotation(xdoc);
return xdoc;
}
public static void PutXDocument(this OpenXmlPart part)
{
var xdoc = part.GetXDocument();
xdoc.PutXDocument(part);
}
public static void PutXDocument(this XDocument xdoc, OpenXmlPart part)
{
if (xdoc != null)
{
using (var xw =
XmlWriter.Create(part.GetStream
(FileMode.Create, FileAccess.Write)))
{
xdoc.Save(xw);
}
}
}
public static XmlDocument GetXmlDocByNamespace(this MainDocumentPart mainPart, string nameSpace)
{
var doc = new XmlDocument();
foreach (var part in mainPart.CustomXmlParts)
{
using (var stream = part.GetStream())
{
if (stream.Length == 0)
{
continue;
}
doc.Load(stream);
if (doc?.DocumentElement?.NamespaceURI == nameSpace)
{
return doc;
}
}
}
return null;
}
private static string GetExementAttributeValue(this XElement dataElement, string query)
{
var cultureElement = dataElement.Descendants(w + query);
if (cultureElement.Any())
{
return cultureElement.First().FirstAttribute.Value;
}
return null;
}
public static List<Tuple<OpenXmlPart, IEnumerable<XElement>>> GetXMLPartsAndBindings(this MainDocumentPart mainPart)
{
var partsAndBindings = new List<Tuple<OpenXmlPart, IEnumerable<XElement>>>();
foreach (var header in mainPart.HeaderParts)
{
var headerDoc = header.GetXDocument();
var headerBinding = headerDoc?.Descendants(w + "dataBinding");
if (headerBinding != null)
{
partsAndBindings.Add(new Tuple<OpenXmlPart, IEnumerable<XElement>>(header, headerBinding));
}
}
foreach (var footer in mainPart.FooterParts)
{
var footerDoc = footer.GetXDocument();
var footerBinding = footerDoc?.Descendants(w + "dataBinding");
if (footerBinding != null)
{
partsAndBindings.Add(new Tuple<OpenXmlPart, IEnumerable<XElement>>(footer, footerBinding));
}
}
var mainXml = mainPart.GetXDocument();
var bindings = mainXml?.Descendants(w + "dataBinding");
if (bindings != null)
{
partsAndBindings.Add(new Tuple<OpenXmlPart, IEnumerable<XElement>>(mainPart, bindings));
}
return partsAndBindings;
}
} Constants: public class EdocsConversionConstants
{
public static readonly XNamespace W = @"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
public const string Myns = @"http://schemas.microsoft.com/office/2006/metadata/properties";
} Let me know if something else needed, thanks in advance for help. |
Hi @Yaroslav-Andrieiev-Net the issue is caused by this line using (var xw =XmlWriter.Create(part.GetStreamFileMode.Create, FileAccess.Write))) in the PutXDocument method. You are trying to open stream that is already open with XmlWriter. public static void PutXDocument(this XDocument xdoc, OpenXmlPart part)
{
if (xdoc != null)
{
using (var xw = part.GetStream())
{
xdoc.Save(xw);
}
}
} As a side note while I was testing your issue I found out that below foreach loop is never entered so you may want to rethink the logic there if that is not expected behaviour foreach (var binding in part.Item2) Let me know how that works for you. Thanks |
Hi @mkaszewiak, It works! Thanks a lot for assistance |
@Yaroslav-Andrieiev-Net You're very welcome! I'm glad to hear that it works for you. |
Describe the bug
Hi everyone, we faced an issue after "DocumentFormat.OpenXml" migration from 2.20.0 to latest 3.1.0 (issue reproduces in versions 3.0.0 - 3.1.0).
It happens on disposal of WordprocessingDocument
Stacktrace:
- System.IO.IOException: Entries cannot be opened multiple times in Update mode. at System.IO.Compression.ZipArchiveEntry.OpenInUpdateMode() at System.IO.Packaging.ZipStreamManager.Open(ZipArchiveEntry zipArchiveEntry, FileAccess streamFileAccess) at System.IO.Packaging.ZipPackagePart.GetStreamCore(FileMode streamFileMode, FileAccess streamFileAccess) at DocumentFormat.OpenXml.Packaging.OpenXmlPart.LoadDomTree[T]() at DocumentFormat.OpenXml.Packaging.MainDocumentPart.get_PartRootElement() at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.SavePartContents(Boolean save) at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Dispose(Boolean disposing) at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Dispose() at Edocs.Infrastructure.Services.Conversion.OpenXMLCorrector.FixSharePointFile(MemoryStream stream, IFileLoggerInfo fileLoggerInfo, String extension)
Issue reproduces only with particular .docx file: File.docx
Code
Extenstion methods:
Thanks in advance for any assistance!
The text was updated successfully, but these errors were encountered: