Skip to content

Commit 4a977b8

Browse files
albinjnul800sebastiaan
authored andcommitted
Fix UmbracoMapper InvalidOperationException due to concurrent modification of inner dictionary (#15830)
1 parent 2fbda6e commit 4a977b8

File tree

1 file changed

+8
-8
lines changed

1 file changed

+8
-8
lines changed

src/Umbraco.Infrastructure/Mapping/UmbracoMapper.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ public class UmbracoMapper : IUmbracoMapper
4343
// note
4444
//
4545
// the outer dictionary *can* be modified, see GetCtor and GetMap, hence have to be ConcurrentDictionary
46-
// the inner dictionaries are never modified and therefore can be simple Dictionary
47-
private readonly ConcurrentDictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors =
46+
// the inner dictionaries can also be modified, see GetCtor and therefore also needs to be a ConcurrentDictionary
47+
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, Func<object, MapperContext, object>>> _ctors =
4848
new();
4949

5050
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<object, object, MapperContext>>> _maps =
@@ -129,7 +129,7 @@ public void Define<TSource, TTarget>(
129129
Type sourceType = typeof(TSource);
130130
Type targetType = typeof(TTarget);
131131

132-
Dictionary<Type, Func<object, MapperContext, object>> sourceCtors = DefineCtors(sourceType);
132+
ConcurrentDictionary<Type, Func<object, MapperContext, object>> sourceCtors = DefineCtors(sourceType);
133133
if (ctor != null)
134134
{
135135
sourceCtors[targetType] = (source, context) => ctor((TSource)source, context)!;
@@ -139,8 +139,8 @@ public void Define<TSource, TTarget>(
139139
sourceMaps[targetType] = (source, target, context) => map((TSource)source, (TTarget)target, context);
140140
}
141141

142-
private Dictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType) =>
143-
_ctors.GetOrAdd(sourceType, _ => new Dictionary<Type, Func<object, MapperContext, object>>());
142+
private ConcurrentDictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType) =>
143+
_ctors.GetOrAdd(sourceType, _ => new ConcurrentDictionary<Type, Func<object, MapperContext, object>>());
144144

145145
private ConcurrentDictionary<Type, Action<object, object, MapperContext>> DefineMaps(Type sourceType) =>
146146
_maps.GetOrAdd(sourceType, _ => new ConcurrentDictionary<Type, Action<object, object, MapperContext>>());
@@ -391,15 +391,15 @@ public TTarget Map<TSource, TTarget>(TSource source, TTarget target, MapperConte
391391
return null;
392392
}
393393

394-
if (_ctors.TryGetValue(sourceType, out Dictionary<Type, Func<object, MapperContext, object>>? sourceCtor) &&
394+
if (_ctors.TryGetValue(sourceType, out ConcurrentDictionary<Type, Func<object, MapperContext, object>>? sourceCtor) &&
395395
sourceCtor.TryGetValue(targetType, out Func<object, MapperContext, object>? ctor))
396396
{
397397
return ctor;
398398
}
399399

400400
// we *may* run this more than once but it does not matter
401401
ctor = null;
402-
foreach ((Type stype, Dictionary<Type, Func<object, MapperContext, object>> sctors) in _ctors)
402+
foreach ((Type stype, ConcurrentDictionary<Type, Func<object, MapperContext, object>> sctors) in _ctors)
403403
{
404404
if (!stype.IsAssignableFrom(sourceType))
405405
{
@@ -427,7 +427,7 @@ public TTarget Map<TSource, TTarget>(TSource source, TTarget target, MapperConte
427427
{
428428
if (!v.ContainsKey(c.Key))
429429
{
430-
v.Add(c.Key, c.Value);
430+
v.TryAdd(c.Key, c.Value);
431431
}
432432
}
433433

0 commit comments

Comments
 (0)