Fix UmbracoMapper InvalidOperationException due to concurrent modification of inner dictionary (#15830)

This commit is contained in:
albinj
2024-03-07 08:41:03 +00:00
committed by Sebastiaan Janssen
parent 2fbda6e64b
commit 4a977b85a2

View File

@@ -43,8 +43,8 @@ public class UmbracoMapper : IUmbracoMapper
// note
//
// the outer dictionary *can* be modified, see GetCtor and GetMap, hence have to be ConcurrentDictionary
// the inner dictionaries are never modified and therefore can be simple Dictionary
private readonly ConcurrentDictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors =
// the inner dictionaries can also be modified, see GetCtor and therefore also needs to be a ConcurrentDictionary
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, Func<object, MapperContext, object>>> _ctors =
new();
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<object, object, MapperContext>>> _maps =
@@ -129,7 +129,7 @@ public class UmbracoMapper : IUmbracoMapper
Type sourceType = typeof(TSource);
Type targetType = typeof(TTarget);
Dictionary<Type, Func<object, MapperContext, object>> sourceCtors = DefineCtors(sourceType);
ConcurrentDictionary<Type, Func<object, MapperContext, object>> sourceCtors = DefineCtors(sourceType);
if (ctor != null)
{
sourceCtors[targetType] = (source, context) => ctor((TSource)source, context)!;
@@ -139,8 +139,8 @@ public class UmbracoMapper : IUmbracoMapper
sourceMaps[targetType] = (source, target, context) => map((TSource)source, (TTarget)target, context);
}
private Dictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType) =>
_ctors.GetOrAdd(sourceType, _ => new Dictionary<Type, Func<object, MapperContext, object>>());
private ConcurrentDictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType) =>
_ctors.GetOrAdd(sourceType, _ => new ConcurrentDictionary<Type, Func<object, MapperContext, object>>());
private ConcurrentDictionary<Type, Action<object, object, MapperContext>> DefineMaps(Type sourceType) =>
_maps.GetOrAdd(sourceType, _ => new ConcurrentDictionary<Type, Action<object, object, MapperContext>>());
@@ -391,7 +391,7 @@ public class UmbracoMapper : IUmbracoMapper
return null;
}
if (_ctors.TryGetValue(sourceType, out Dictionary<Type, Func<object, MapperContext, object>>? sourceCtor) &&
if (_ctors.TryGetValue(sourceType, out ConcurrentDictionary<Type, Func<object, MapperContext, object>>? sourceCtor) &&
sourceCtor.TryGetValue(targetType, out Func<object, MapperContext, object>? ctor))
{
return ctor;
@@ -399,7 +399,7 @@ public class UmbracoMapper : IUmbracoMapper
// we *may* run this more than once but it does not matter
ctor = null;
foreach ((Type stype, Dictionary<Type, Func<object, MapperContext, object>> sctors) in _ctors)
foreach ((Type stype, ConcurrentDictionary<Type, Func<object, MapperContext, object>> sctors) in _ctors)
{
if (!stype.IsAssignableFrom(sourceType))
{
@@ -427,7 +427,7 @@ public class UmbracoMapper : IUmbracoMapper
{
if (!v.ContainsKey(c.Key))
{
v.Add(c.Key, c.Value);
v.TryAdd(c.Key, c.Value);
}
}