From 021be875ee4e37bb2ee546ce2c2bec1721dcc519 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 2 Dec 2019 13:42:31 +0000 Subject: [PATCH] [Core] Make MSBuildPropertyGroupEvaluated thread safe Adding a new .json file to a ASP.NET Core 3.1 project resulted in the files not being displayed in the Properties folder due to the project configuration's Properties being updated on a background thread on saving and the UI thread reading these properties to determine if a file is visible in the Solution pad. Switch to using a concurrent dictionary in MSBuildPropertyGroupEvaluated. System.InvalidOperationException: Collection was modified; enumeration operation may not execute. at System.Collections.Generic.Dictionary`2+ValueCollection+Enumerator[TKey,TValue].MoveNext () [0x00085] in mono-x64/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs:1628 at MonoDevelop.Projects.MSBuild.MSBuildEvaluatedPropertyCollection+d__11.MoveNext () [0x0008e] in monodevelop/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroupEvaluated.cs:207 at MonoDevelop.Projects.Project+d__143.MoveNext () [0x0017d] in monodevelop/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs:1231 at MonoDevelop.Ide.Gui.Pads.ProjectPad.FolderNodeBuilder.GetFolderContent (MonoDevelop.Projects.Project project, System.String folder, System.Collections.Generic.List`1[MonoDevelop.Projects.ProjectFile]& files, System.Collections.Generic.List`1[System.String]& folders) [0x00149] in monodevelop/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs:87 at MonoDevelop.Ide.Gui.Pads.ProjectPad.FolderNodeBuilder.BuildChildNodes (MonoDevelop.Ide.Gui.Components.ITreeBuilder builder, System.Object dataObject) [0x00048] in monodevelop/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs:74 at MonoDevelop.Ide.Gui.Components.ExtensibleTreeView+TransactedTreeBuilder.FillNode () [0x00082] in monodevelop/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/TransactedTreeBuilder.cs:522 --- .../MSBuildPropertyGroupEvaluated.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroupEvaluated.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroupEvaluated.cs index 18d155a6d44..31025499fb2 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroupEvaluated.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroupEvaluated.cs @@ -24,6 +24,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Xml.Linq; using MonoDevelop.Core; @@ -32,7 +33,7 @@ namespace MonoDevelop.Projects.MSBuild { class MSBuildPropertyGroupEvaluated: MSBuildNode, IMSBuildPropertyGroupEvaluated, IMSBuildProjectObject { - protected Dictionary properties = new Dictionary (StringComparer.OrdinalIgnoreCase); + protected ConcurrentDictionary properties = new ConcurrentDictionary (StringComparer.OrdinalIgnoreCase); MSBuildEngine engine; internal MSBuildPropertyGroupEvaluated (MSBuildProject parent) @@ -70,7 +71,7 @@ internal void SetProperty (string key, IMSBuildPropertyEvaluated value) internal void SetProperties (Dictionary properties) { - this.properties = properties; + this.properties = new ConcurrentDictionary (properties, StringComparer.OrdinalIgnoreCase); } public IEnumerable GetProperties () @@ -80,7 +81,7 @@ public IEnumerable GetProperties () internal bool RemoveProperty (string name) { - return properties.Remove (name); + return properties.TryRemove (name, out _); } public string GetValue (string name, string defaultValue = null) @@ -280,7 +281,7 @@ void IPropertyGroupListener.PropertyRemoved (MSBuildProperty prop) // that property group property. if (ep.IsNew || !prop.IsNew) { ep.IsNew = false; - properties.Remove (ep.Name); + properties.TryRemove (ep.Name, out _); } } }