diff --git a/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs b/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs index 8fd5a110d..9da790d1c 100644 --- a/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs +++ b/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs @@ -175,6 +175,33 @@ public void ShouldApplyMapperConfigurationsInOrder() } } + // See https://github.com/agileobjects/AgileMapper/issues/91 + [Fact] + public void ShouldApplyMapperConfigurationsInOrderAutomatically() + { + var values = new List { 1, 2, 3 }; + var provider = new StubServiceProvider(values); + + var grandParent = new GrandParent + { + DatChild = new Parent { MyChild = new Child() } + }; + + using (var mapper = Mapper.CreateNew()) + { + mapper.WhenMapping + .UseServiceProvider(provider) + .UseConfigurations + .From(); + + var result = mapper.Map(grandParent).ToANew(); + + result.MyChild.ShouldNotBeNull(); + result.MyChild.MyChild.ShouldNotBeNull(); + result.MyChild.MyChild.IsMyCountGtrZero.ShouldBeTrue(); + } + } + #region Helper Classes public class PfiToPfsMapperConfiguration : MapperConfiguration diff --git a/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurationsIncorrectly.cs b/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurationsIncorrectly.cs index c3935e026..cb3c6f066 100644 --- a/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurationsIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurationsIncorrectly.cs @@ -75,19 +75,20 @@ public void ShouldErrorIfDuplicateConfigurationAdded() } [Fact] - public void ShouldErrorIfDependentConfigurationAddedBeforeDependedOnConfiguration() + public void ShouldErrorIfRedundantConfigurationAdded() { var configEx = Should.Throw(() => { using (var mapper = Mapper.CreateNew()) { mapper.WhenMapping.UseConfigurations - .From(); + .From() + .From(); } }); - configEx.Message.ShouldContain("ParentMapperConfiguration"); configEx.Message.ShouldContain("ChildMapperConfiguration"); + configEx.Message.ShouldContain("already been applied"); } [Fact] diff --git a/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs b/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs index 3ce426d76..43bef710f 100644 --- a/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs +++ b/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs @@ -84,8 +84,7 @@ public MapperConfigurationSpecifier From(IEnumerable assemblies, Func< ThrowIfInvalidAssembliesSupplied(matchingAssemblies.Any(), nullSupplied: false); - ApplyConfigurationsIn(matchingAssemblies.SelectMany(QueryConfigurationTypesIn)); - return this; + return ApplyConfigurationsIn(matchingAssemblies.SelectMany(QueryConfigurationTypesIn)); } /// @@ -101,12 +100,10 @@ public MapperConfigurationSpecifier From() where TConfiguration : MapperConfiguration, new() { ThrowIfConfigurationAlreadyApplied(typeof(TConfiguration)); - ThrowIfDependedOnConfigurationNotApplied(typeof(TConfiguration)); - var configuration = new TConfiguration(); + var configurationTypeChain = GetAllConfigurationTypesFor(typeof(TConfiguration)); - Apply(configuration); - return this; + return ApplyConfigurationsIn(configurationTypeChain); } private void ThrowIfConfigurationAlreadyApplied(Type configurationType) @@ -118,29 +115,17 @@ private void ThrowIfConfigurationAlreadyApplied(Type configurationType) } } - private void ThrowIfDependedOnConfigurationNotApplied(Type configurationType) + private static IEnumerable GetAllConfigurationTypesFor(Type configurationType) { - var dependedOnTypes = GetDependedOnConfigurationTypesFor(configurationType); - - if (dependedOnTypes.None()) - { - return; - } - - var missingDependencies = dependedOnTypes - .Filter(t => !ConfigurationApplied(t)) - .ToArray(); - - if (missingDependencies.None()) + foreach (var dependedOnType in GetDependedOnConfigurationTypesFor(configurationType)) { - return; + foreach (var nestedDependedOnType in GetAllConfigurationTypesFor(dependedOnType)) + { + yield return nestedDependedOnType; + } } - var configurationTypeName = configurationType.GetFriendlyName(); - var dependencyNames = missingDependencies.Project(d => d.GetFriendlyName()).Join(", "); - - throw new MappingConfigurationException( - $"Configuration {configurationTypeName} must be registered after depended-on configuration(s) {dependencyNames}"); + yield return configurationType; } private bool ConfigurationApplied(Type configurationType) @@ -158,12 +143,9 @@ private bool ConfigurationApplied(Type configurationType) /// to be registered. /// public MapperConfigurationSpecifier FromAssemblyOf() - { - ApplyConfigurationsIn(QueryConfigurationTypesIn(typeof(T).GetAssembly())); - return this; - } + => ApplyConfigurationsIn(QueryConfigurationTypesIn(typeof(T).GetAssembly())); - private void ApplyConfigurationsIn(IEnumerable configurationTypes) + private MapperConfigurationSpecifier ApplyConfigurationsIn(IEnumerable configurationTypes) { var configurationData = configurationTypes .Select(t => new ConfigurationData(t)) @@ -172,7 +154,7 @@ private void ApplyConfigurationsIn(IEnumerable configurationTypes) if (configurationData.None(d => d.DependedOnConfigurationTypes.Any())) { Apply(configurationData.Project(d => d.Configuration)); - return; + return this; } var configurationCount = configurationData.Count; @@ -213,6 +195,7 @@ private void ApplyConfigurationsIn(IEnumerable configurationTypes) .Project(kvp => configurationDataByType[kvp.Key].Configuration); Apply(orderedConfigurations); + return this; } private static void InsertWithOrder(