Browse Source

Developed automapper module fundamentally.

pull/96/head
Halil İbrahim Kalkan 9 years ago
parent
commit
ce2a3a2535
  1. 9
      Volo.Abp.sln
  2. 19
      src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConfiguration.cs
  3. 190
      src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs
  4. 40
      src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperOptions.cs
  5. 7
      src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AutoMapperObjectMapper.cs
  6. 17
      src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/IAbpAutoMapperConfiguration.cs
  7. 9
      src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/IMapperAccessor.cs
  8. 9
      src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/MapperAccessor.cs
  9. 3
      src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs
  10. 6
      src/Volo.Abp/Volo/Abp/Reflection/TypeFinder.cs
  11. 24
      test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj
  12. 17
      test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Registration_Tests.cs
  13. 14
      test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutofacTestModule.cs

9
Volo.Abp.sln

@ -114,7 +114,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Autofac.Tests", "t
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Castle.Core.Tests", "test\Volo.Abp.Castle.Core.Tests\Volo.Abp.Castle.Core.Tests.csproj", "{CE12E5C2-7B3E-4637-B6A3-274BB5C3DE16}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AutoMapper", "src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj", "{D2F3594F-E2B9-4338-A022-F00C4E9A14C3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AutoMapper", "src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj", "{D2F3594F-E2B9-4338-A022-F00C4E9A14C3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AutoMapper.Tests", "test\Volo.Abp.AutoMapper.Tests\Volo.Abp.AutoMapper.Tests.csproj", "{8343BE23-6A7B-4C58-BF0D-95188B11B180}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -282,6 +284,10 @@ Global
{D2F3594F-E2B9-4338-A022-F00C4E9A14C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2F3594F-E2B9-4338-A022-F00C4E9A14C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2F3594F-E2B9-4338-A022-F00C4E9A14C3}.Release|Any CPU.Build.0 = Release|Any CPU
{8343BE23-6A7B-4C58-BF0D-95188B11B180}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8343BE23-6A7B-4C58-BF0D-95188B11B180}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8343BE23-6A7B-4C58-BF0D-95188B11B180}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8343BE23-6A7B-4C58-BF0D-95188B11B180}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -336,5 +342,6 @@ Global
{D8BE64D2-BD83-40F5-9783-D7FDDF668C45} = {37087D1B-3693-4E96-983D-A69F210BDE53}
{CE12E5C2-7B3E-4637-B6A3-274BB5C3DE16} = {37087D1B-3693-4E96-983D-A69F210BDE53}
{D2F3594F-E2B9-4338-A022-F00C4E9A14C3} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
{8343BE23-6A7B-4C58-BF0D-95188B11B180} = {37087D1B-3693-4E96-983D-A69F210BDE53}
EndGlobalSection
EndGlobal

19
src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConfiguration.cs

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using AutoMapper;
namespace Volo.Abp.AutoMapper
{
public class AbpAutoMapperConfiguration : IAbpAutoMapperConfiguration
{
public List<Action<IMapperConfigurationExpression>> Configurators { get; }
public bool UseStaticMapper { get; set; }
public AbpAutoMapperConfiguration()
{
UseStaticMapper = true;
Configurators = new List<Action<IMapperConfigurationExpression>>();
}
}
}

190
src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs

@ -1,98 +1,114 @@
using System;
using System.Linq;
using System.Reflection;
using AutoMapper;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Modularity;
using Volo.Abp.Reflection;
namespace Volo.Abp.AutoMapper
{
public class AbpAutoMapperModule : AbpModule
{
//private readonly ITypeFinder _typeFinder;
//private static volatile bool _createdMappingsBefore;
//private static readonly object SyncObj = new object();
//public AbpAutoMapperModule(ITypeFinder typeFinder)
//{
// _typeFinder = typeFinder;
//}
//public override void PreInitialize()
//{
// IocManager.Register<IAbpAutoMapperConfiguration, AbpAutoMapperConfiguration>();
// Configuration.ReplaceService<ObjectMapping.IObjectMapper, AutoMapperObjectMapper>();
// Configuration.Modules.AbpAutoMapper().Configurators.Add(CreateCoreMappings);
//}
//public override void PostInitialize()
//{
// CreateMappings();
//}
//private void CreateMappings()
//{
// lock (SyncObj)
// {
// Action<IMapperConfigurationExpression> configurer = configuration =>
// {
// FindAndAutoMapTypes(configuration);
// foreach (var configurator in Configuration.Modules.AbpAutoMapper().Configurators)
// {
// configurator(configuration);
// }
// };
// if (Configuration.Modules.AbpAutoMapper().UseStaticMapper)
// {
// //We should prevent duplicate mapping in an application, since Mapper is static.
// if (!_createdMappingsBefore)
// {
// Mapper.Initialize(configurer);
// _createdMappingsBefore = true;
// }
// IocManager.IocContainer.Register(
// Component.For<IMapper>().Instance(Mapper.Instance).LifestyleSingleton()
// );
// }
// else
// {
// var config = new MapperConfiguration(configurer);
// IocManager.IocContainer.Register(
// Component.For<IMapper>().Instance(config.CreateMapper()).LifestyleSingleton()
// );
// }
// }
//}
//private void FindAndAutoMapTypes(IMapperConfigurationExpression configuration)
//{
// var types = _typeFinder.Find(type =>
// {
// var typeInfo = type.GetTypeInfo();
// return typeInfo.IsDefined(typeof(AutoMapAttribute)) ||
// typeInfo.IsDefined(typeof(AutoMapFromAttribute)) ||
// typeInfo.IsDefined(typeof(AutoMapToAttribute));
// }
// );
// Logger<>.DebugFormat("Found {0} classes define auto mapping attributes", types.Length);
// foreach (var type in types)
// {
// Logger<>.Debug(type.FullName);
// configuration.CreateAutoAttributeMaps(type);
// }
//}
//private void CreateCoreMappings(IMapperConfigurationExpression configuration)
//{
// var localizationContext = IocManager.Resolve<ILocalizationContext>();
// configuration.CreateMap<ILocalizableString, string>().ConvertUsing(ls => ls?.Localize(localizationContext));
// configuration.CreateMap<LocalizableString, string>().ConvertUsing(ls => ls == null ? null : localizationContext.LocalizationManager.GetString(ls));
//}
private static volatile bool _createdMappingsBefore;
private static readonly object SyncObj = new object();
public override void ConfigureServices(IServiceCollection services)
{
services.AddAssemblyOf<AbpAutoMapperModule>();
var mapperAccessor = new MapperAccessor();
services.AddSingleton<IMapperAccessor>(_ => mapperAccessor);
services.AddSingleton<MapperAccessor>(_ => mapperAccessor);
services.Configure<AbpAutoMapperOptions>(options =>
{
options.Configurators.Add(CreateCoreMappings);
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
CreateMappings(context.ServiceProvider);
}
private void CreateMappings(IServiceProvider serviceProvider)
{
lock (SyncObj)
{
using (var scope = serviceProvider.CreateScope())
{
var options = scope.ServiceProvider.GetRequiredService<IOptions<AbpAutoMapperOptions>>().Value;
void ConfigureAll(IAbpAutoMapperConfigurationContext ctx)
{
FindAndAutoMapTypes(ctx);
foreach (var configurator in options.Configurators)
{
configurator(ctx);
}
}
if (options.UseStaticMapper)
{
//We should prevent duplicate mapping in an application, since Mapper is static.
if (!_createdMappingsBefore)
{
Mapper.Initialize(mapperConfigurationExpression =>
{
ConfigureAll(new AbpAutoMapperConfigurationContext(mapperConfigurationExpression, scope.ServiceProvider));
});
_createdMappingsBefore = true;
}
scope.ServiceProvider.GetRequiredService<MapperAccessor>().Mapper = Mapper.Instance;
}
else
{
var config = new MapperConfiguration(mapperConfigurationExpression =>
{
ConfigureAll(new AbpAutoMapperConfigurationContext(mapperConfigurationExpression, scope.ServiceProvider));
});
scope.ServiceProvider.GetRequiredService<MapperAccessor>().Mapper = config.CreateMapper();
}
}
}
}
private void FindAndAutoMapTypes(IAbpAutoMapperConfigurationContext context)
{
var typeFinder = context.ServiceProvider.GetRequiredService<ITypeFinder>();
var logger = context.ServiceProvider.GetRequiredService<ILogger<AbpAutoMapperModule>>();
var types = typeFinder.Types.Where(type =>
{
var typeInfo = type.GetTypeInfo();
return typeInfo.IsDefined(typeof(AutoMapAttribute)) ||
typeInfo.IsDefined(typeof(AutoMapFromAttribute)) ||
typeInfo.IsDefined(typeof(AutoMapToAttribute));
}
).ToArray();
logger.LogDebug($"Found {types.Length} classes define auto mapping attributes:");
foreach (var type in types)
{
logger.LogDebug(type.FullName);
context.MapperConfigurationExpression.CreateAutoAttributeMaps(type);
}
}
private void CreateCoreMappings(IAbpAutoMapperConfigurationContext context)
{
//Will be done when localization system completed
//var localizationContext = IocManager.Resolve<ILocalizationContext>();
//configuration.CreateMap<ILocalizableString, string>().ConvertUsing(ls => ls?.Localize(localizationContext));
//configuration.CreateMap<LocalizableString, string>().ConvertUsing(ls => ls == null ? null : localizationContext.LocalizationManager.GetString(ls));
}
}
}

40
src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperOptions.cs

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using AutoMapper;
namespace Volo.Abp.AutoMapper
{
public class AbpAutoMapperOptions
{
public List<Action<IAbpAutoMapperConfigurationContext>> Configurators { get; }
public bool UseStaticMapper { get; set; }
public AbpAutoMapperOptions()
{
UseStaticMapper = true;
Configurators = new List<Action<IAbpAutoMapperConfigurationContext>>();
}
}
public interface IAbpAutoMapperConfigurationContext
{
IMapperConfigurationExpression MapperConfigurationExpression { get; }
IServiceProvider ServiceProvider { get; }
}
public class AbpAutoMapperConfigurationContext : IAbpAutoMapperConfigurationContext
{
public IMapperConfigurationExpression MapperConfigurationExpression { get; }
public IServiceProvider ServiceProvider { get; }
public AbpAutoMapperConfigurationContext(
IMapperConfigurationExpression mapperConfigurationExpression,
IServiceProvider serviceProvider)
{
MapperConfigurationExpression = mapperConfigurationExpression;
ServiceProvider = serviceProvider;
}
}
}

7
src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AutoMapperObjectMapper.cs

@ -1,14 +1,17 @@
using AutoMapper;
using Microsoft.Extensions.DependencyInjection;
using Volo.DependencyInjection;
namespace Volo.Abp.AutoMapper
{
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
public class AutoMapperObjectMapper : Volo.Abp.ObjectMapping.IObjectMapper
{
private readonly IMapper _mapper;
public AutoMapperObjectMapper(IMapper mapper)
public AutoMapperObjectMapper(IMapperAccessor mapper)
{
_mapper = mapper;
_mapper = mapper.Mapper;
}
public TDestination Map<TDestination>(object source)

17
src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/IAbpAutoMapperConfiguration.cs

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using AutoMapper;
namespace Volo.Abp.AutoMapper
{
public interface IAbpAutoMapperConfiguration
{
List<Action<IMapperConfigurationExpression>> Configurators { get; }
/// <summary>
/// Use static <see cref="Mapper.Instance"/>.
/// Default: true.
/// </summary>
bool UseStaticMapper { get; set; }
}
}

9
src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/IMapperAccessor.cs

@ -0,0 +1,9 @@
using AutoMapper;
namespace Volo.Abp.AutoMapper
{
public interface IMapperAccessor
{
IMapper Mapper { get; }
}
}

9
src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/MapperAccessor.cs

@ -0,0 +1,9 @@
using AutoMapper;
namespace Volo.Abp.AutoMapper
{
public class MapperAccessor : IMapperAccessor
{
public IMapper Mapper { get; set; }
}
}

3
src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs

@ -5,10 +5,11 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using Volo.Abp.Modularity;
using Volo.DependencyInjection;
namespace Volo.Abp.Reflection
{
public class AssemblyFinder : IAssemblyFinder
public class AssemblyFinder : IAssemblyFinder, ITransientDependency
{
private readonly IModuleContainer _moduleContainer;

6
src/Volo.Abp/Volo/Abp/Reflection/TypeFinder.cs

@ -4,13 +4,13 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.Extensions.Logging;
using Volo.DependencyInjection;
using Volo.ExtensionMethods.Collections.Generic;
namespace Volo.Abp.Reflection
{
//TODO: Write unit tests!
public class TypeFinder : ITypeFinder
//TODO: What if we need to this type finder while registering dependencies?
public class TypeFinder : ITypeFinder, ITransientDependency
{
private readonly IAssemblyFinder _assemblyFinder;
private readonly ILogger<TypeFinder> _logger;

24
test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<AssemblyName>Volo.Abp.AutoMapper.Tests</AssemblyName>
<PackageId>Volo.Abp.AutoMapper.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

17
test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Registration_Tests.cs

@ -0,0 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.ObjectMapping;
using Volo.Abp.TestBase;
using Xunit;
namespace Volo.Abp.AutoMapper
{
public class AbpAutoMapperModule_Registration_Tests : AbpIntegratedTest<AutoMapperTestModule>
{
[Fact]
public void Should_Replace_ObjectMapper()
{
var objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
Assert.True(objectMapper is AutoMapperObjectMapper);
}
}
}

14
test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutofacTestModule.cs

@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace Volo.Abp.AutoMapper
{
[DependsOn(typeof(AbpAutoMapperModule))]
public class AutoMapperTestModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAssemblyOf<AbpAutoMapperModule>();
}
}
}
Loading…
Cancel
Save