-
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
SpredsheetDocument.Save() InvalidOperationException (Collection was modified) #1659
Comments
I stepped through PackageFeatureBase.UpdateCachedItems() in DocumentFormat.OpenXml.Features Anyway, my code does reach the 'Remove' part and deletes removed parts. I'm not sure if this should be happening. |
@twsouthwick can you take a look? |
@SirParser can you provide a repro for me? |
Thanks @AlfredHellstern and @twsouthwick |
Oh - you're loading it manually through powershell and on an older version of powershell. You should be resolving the .net framework assemblies if you want to do as you're on Powershell 5.1 However, resolving them manually is difficult given powershell vs powershell core. We could potentially package them up as a powershell module so that things are resolved correctly. I haven't done that for a while, but I'd be open for taking a PR to enable an official powershell module that would set things up correctly. |
For more technical details, on .NET 6, enumerating over a dictionary that has had items removed is now supported. So, we special case our compilation to have a different pathway for .NET 6+ vs others: Open-XML-SDK/src/DocumentFormat.OpenXml.Framework/Features/PackageFeatureBase.cs Lines 46 to 82 in 35b91d3
|
Thanks @twsouthwick. Please excuse my ignorance, but my understanding so far was that netstandard2.0 dll's should work fine regardless of the target .Net environment. Can you direct me to some link, or share more info that explains this in more detail:
From what you wrote I understand that my PS script uses wrong version of PackageFeatureBase. It uses version with code designed for NET6_0_OR_GREATER (with direct key removal instead of via List? unused). I don't understand why this is so considering I'm explicitly loading the netstandard2.0 dll version. How can I force the PS script to use the correct version of dll? Or should I add .Net Framework 4.6 to the target frameworks of my library and use it instead of netstandard2.0? |
I'll be out of town the next few days but let me try to answer these. . NET standard in general works on all platforms but we have a specific framework build for actually running it on framework. This is due to a number of weirdness with the Windowsbase.dll implementation of the packaging Apis. So, things probably won't work well to use the net standard build on framework. I've never tested it and we expect people to use nuget to resolve the best platform assemblies. I would try resolving the framework version of the assemblies and see if that works. I'm not opposed to an official powers he'll module to simplify this resolution so if you want to submit a PR, happy to consider it. The specific issue you're hitting is a weird one to hit even with the standard libs - I wouldn't expect it. I haven't had time to repro, but will try end of next week when I'm back |
Hi Taylor, I haven't had time to look into this in the last few months, but some requirement popped up recently and I ran into this issue again. This time I wanted to use an Excel template with a table and that triggered again the UpdateCachedItems() method and the "Collection was modified..." error. Regards, PM |
Here's the proposed change: protected void UpdateCachedItems()
{
if (_parts is null)
{
return;
}
#if !NET6_0_OR_GREATER
List<Uri>? unused = null;
#endif
foreach (var part in _parts)
{
if (Package.PartExists(part.Key))
{
part.Value.Part = Package.GetPart(part.Key);
}
else
{
#if NET6_0_OR_GREATER
_parts.Remove(part.Key);
#else
(unused ??= new()).Add(part.Key);
#endif
}
// CHANGE START
}
#if !NET6_0_OR_GREATER
if (unused is not null)
{
foreach (var uri in unused)
{
_parts.Remove(uri);
}
}
#endif
// CHANGE END
} |
@twsouthwick can you have a look? |
When executing SpreadsheetDocument.Save() (i.e. base class OpenXmlPackage.Save()) I'm getting the following error:
InvalidOperationException
Collection was modified; enumeration operation may not execute.
StackTrace:
[DBG]: PS ...>> $_.Exception.InnerException.StackTrace
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
at DocumentFormat.OpenXml.Features.PackageFeatureBase.UpdateCachedItems()
at DocumentFormat.OpenXml.Packaging.Builder.SavePackageExtensions.SaveablePackage.Save()
at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Save()
This happens only when I'm using the library in a PowerShell script.
While debugging in JetBrains Rider (on the same machine) it works OK.
It looks like something about the 'Cached Items' is handled differently when library is used after installing in
'C:\Program Files\PackageManagement\NuGet\Packages', comparing to debugging it in IDE.
Has anyone encountered this issue?
Environment:
Windows Server 2016
PowerShell 5.1
IDE: JetBrains Rider 2023.3.3
DocumentFormat.OpenXml.3.0.0
The text was updated successfully, but these errors were encountered: