Skip to content

Commit 094a2c1

Browse files
authored
Merge pull request #1848 from lbargaoanu/RegistryMapper
Avoid static state; Mapper registry setup moved to mapper configuration instead of its own list
2 parents 09749e8 + 63033d2 commit 094a2c1

File tree

7 files changed

+67
-37
lines changed

7 files changed

+67
-37
lines changed

src/AutoMapper/Configuration/MapperConfigurationExpression.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public class MapperConfigurationExpression : Profile, IMapperConfigurationExpres
1313
public MapperConfigurationExpression() : base("")
1414
{
1515
IncludeSourceExtensionMethods(typeof(Enumerable));
16+
17+
Mappers = MapperRegistry.Mappers();
1618
}
1719

1820
public IEnumerable<IProfileConfiguration> Profiles => _profiles;
@@ -21,6 +23,8 @@ public MapperConfigurationExpression() : base("")
2123
public void CreateProfile(string profileName, Action<IProfileExpression> config)
2224
=> AddProfile(new NamedProfile(profileName, config));
2325

26+
public IList<IObjectMapper> Mappers { get; }
27+
2428
private class NamedProfile : Profile
2529
{
2630
public NamedProfile(string profileName, Action<IProfileExpression> config) : base(profileName, config)

src/AutoMapper/IMapperConfigurationExpression.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,10 @@ public interface IMapperConfigurationExpression : IProfileExpression
7777
/// <param name="profileName">Profile name, must be unique</param>
7878
/// <param name="config">Profile configuration</param>
7979
void CreateProfile(string profileName, Action<IProfileExpression> config);
80+
81+
/// <summary>
82+
/// Object mappers
83+
/// </summary>
84+
IList<IObjectMapper> Mappers { get; }
8085
}
8186
}

src/AutoMapper/MapperConfiguration.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,8 @@ public class MapperConfiguration : IConfigurationProvider
2323
private readonly ConfigurationValidator _validator;
2424

2525
public MapperConfiguration(MapperConfigurationExpression configurationExpression)
26-
: this(configurationExpression, MapperRegistry.Mappers)
2726
{
28-
}
29-
30-
public MapperConfiguration(MapperConfigurationExpression configurationExpression, IEnumerable<IObjectMapper> mappers)
31-
{
32-
_mappers = mappers;
27+
_mappers = configurationExpression.Mappers.ToArray();
3328
_mapPlanCache = new LockingConcurrentDictionary<MapRequest, MapperFuncs>(CreateMapperFuncs);
3429
_validator = new ConfigurationValidator(this);
3530
ExpressionBuilder = new ExpressionBuilder(this);
@@ -43,12 +38,8 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression
4338
Seal();
4439
}
4540

46-
public MapperConfiguration(Action<IMapperConfigurationExpression> configure) : this(configure, MapperRegistry.Mappers)
47-
{
48-
}
49-
50-
public MapperConfiguration(Action<IMapperConfigurationExpression> configure, IEnumerable<IObjectMapper> mappers)
51-
: this(Build(configure), mappers)
41+
public MapperConfiguration(Action<IMapperConfigurationExpression> configure)
42+
: this(Build(configure))
5243
{
5344
}
5445

src/AutoMapper/Mappers/MapperRegistry.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
namespace AutoMapper.Mappers
44
{
5-
public static class MapperRegistry
5+
internal static class MapperRegistry
66
{
7-
private static readonly IObjectMapper[] _initialMappers =
7+
public static IList<IObjectMapper> Mappers() => new List<IObjectMapper>
88
{
99
new NullableSourceMapper(),
1010
new ExpressionMapper(),
@@ -34,21 +34,5 @@ public static class MapperRegistry
3434
new FromDynamicMapper(),
3535
new ToDynamicMapper()
3636
};
37-
38-
private static readonly List<IObjectMapper> _mappers = new List<IObjectMapper>(_initialMappers);
39-
40-
/// <summary>
41-
/// Extension point for modifying list of object mappers
42-
/// </summary>
43-
public static IList<IObjectMapper> Mappers => _mappers;
44-
45-
/// <summary>
46-
/// Reset mapper registry to built-in values
47-
/// </summary>
48-
public static void Reset()
49-
{
50-
_mappers.Clear();
51-
_mappers.AddRange(_initialMappers);
52-
}
5337
}
5438
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using Xunit;
3+
using AutoMapper;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using System.Diagnostics;
7+
using System.Runtime.ExceptionServices;
8+
9+
namespace AutoMapper.UnitTests
10+
{
11+
public class ConvertMapperThreading
12+
{
13+
class Source
14+
{
15+
public string Number { get; set; }
16+
}
17+
18+
class Destination
19+
{
20+
public int Number { get; set; }
21+
}
22+
23+
[Fact]
24+
public void Should_work()
25+
{
26+
var tasks = Enumerable.Range(0, 5).Select(i => Task.Factory.StartNew(() =>
27+
{
28+
new MapperConfiguration(c => c.CreateMap<Source, Destination>());
29+
})).ToArray();
30+
try
31+
{
32+
Task.WaitAll(tasks);
33+
}
34+
catch(AggregateException ex)
35+
{
36+
ex.Handle(e =>
37+
{
38+
if(e is InvalidOperationException)
39+
{
40+
ExceptionDispatchInfo.Capture(e).Throw();
41+
}
42+
return false;
43+
});
44+
}
45+
}
46+
}
47+
}

src/UnitTests/Mappers/CustomMapperTests.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,11 @@ namespace AutoMapper.UnitTests.Mappers
1010
{
1111
public class When_adding_a_custom_mapper : NonValidatingSpecBase
1212
{
13-
public When_adding_a_custom_mapper()
14-
{
15-
MapperRegistry.Mappers.Insert(0, new TestObjectMapper());
16-
}
17-
1813
protected override MapperConfiguration Configuration { get; } = new MapperConfiguration(cfg =>
1914
{
2015
cfg.CreateMap<ClassA, ClassB>()
2116
.ForMember(dest => dest.Destination, opt => opt.MapFrom(src => src.Source));
17+
cfg.Mappers.Add(new TestObjectMapper());
2218
});
2319

2420
[Fact]
@@ -78,7 +74,8 @@ public class When_adding_a_simple_custom_mapper : AutoMapperSpecBase
7874
{
7975
cfg.CreateMap<ClassA, ClassB>()
8076
.ForMember(dest => dest.Destination, opt => opt.MapFrom(src => src.Source));
81-
}, MapperRegistry.Mappers.Concat(new[] { new TestObjectMapper() }));
77+
cfg.Mappers.Add(new TestObjectMapper());
78+
});
8279

8380
protected override void Because_of()
8481
{
@@ -162,7 +159,8 @@ public override string Map(object source, string destination, ResolutionContext
162159
protected override MapperConfiguration Configuration => new MapperConfiguration(cfg =>
163160
{
164161
cfg.CreateMap<Source, Destination>();
165-
}, new[] { new EnumMapper() }.Concat(MapperRegistry.Mappers));
162+
cfg.Mappers.Insert(0, new EnumMapper());
163+
});
166164

167165
protected override void Because_of()
168166
{

src/UnitTests/UnitTests.Net4.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
<Compile Include="AssertionExtensions.cs" />
9494
<Compile Include="BasicFlattening.cs" />
9595
<Compile Include="Bug\ConventionCreateMapsWithCircularReference.cs" />
96+
<Compile Include="Bug\ConvertMapperThreading.cs" />
9697
<Compile Include="Bug\DeepCloningBug.cs" />
9798
<Compile Include="Bug\ForAllMembersAndDoNotUseDestinationValue.cs" />
9899
<Compile Include="Bug\InterfaceMultipleInheritance.cs" />

0 commit comments

Comments
 (0)