Created DefaultObjectMapper and implemented specific mappers.

pull/96/head
Halil İbrahim Kalkan 8 years ago
parent 5afe67a976
commit 05d84a60e4

@ -1,25 +1,28 @@
using AutoMapper;
using System;
using AutoMapper;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.ObjectMapping;
using Volo.DependencyInjection;
namespace Volo.Abp.AutoMapper
{
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
public class AutoMapperObjectMapper : Volo.Abp.ObjectMapping.IObjectMapper
public class AutoMapperObjectMapper : DefaultObjectMapper
{
private readonly IMapper _mapper;
public AutoMapperObjectMapper(IMapperAccessor mapper)
public AutoMapperObjectMapper(IMapperAccessor mapper, IServiceProvider serviceProvider)
: base(serviceProvider)
{
_mapper = mapper.Mapper;
}
public TDestination Map<TDestination>(object source)
protected override TDestination AutoMap<TSource, TDestination>(object source)
{
return _mapper.Map<TDestination>(source);
}
public TDestination Map<TSource, TDestination>(TSource source, TDestination destination)
protected override TDestination AutoMap<TSource, TDestination>(TSource source, TDestination destination)
{
return _mapper.Map(source, destination);
}

@ -0,0 +1,68 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.DependencyInjection;
namespace Volo.Abp.ObjectMapping
{
//TODO: It can be slow to always check if service is available. Test it and optimize if necessary.
public class DefaultObjectMapper : IObjectMapper, ISingletonDependency
{
private readonly IServiceProvider _serviceProvider;
public DefaultObjectMapper(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public virtual TDestination Map<TSource, TDestination>(TSource source)
{
if (source == null)
{
return default(TDestination);
}
//Check if a specific mapper is registered
using (var scope = _serviceProvider.CreateScope())
{
var specificMapper = scope.ServiceProvider.GetService<IObjectMapper<TSource, TDestination>>();
if (specificMapper != null)
{
return specificMapper.Map(source);
}
}
return AutoMap<TSource, TDestination>(source);
}
public virtual TDestination Map<TSource, TDestination>(TSource source, TDestination destination)
{
if (source == null)
{
return default(TDestination);
}
//Check if a specific mapper is registered
using (var scope = _serviceProvider.CreateScope())
{
var specificMapper = scope.ServiceProvider.GetService<IObjectMapper<TSource, TDestination>>();
if (specificMapper != null)
{
return specificMapper.Map(source, destination);
}
}
return AutoMap(source, destination);
}
protected virtual TDestination AutoMap<TSource, TDestination>(object source)
{
throw new NotImplementedException($"Can not map from given object ({source}) to {typeof(TDestination).AssemblyQualifiedName}.");
}
protected virtual TDestination AutoMap<TSource, TDestination>(TSource source, TDestination destination)
{
throw new NotImplementedException($"Can no map from {typeof(TSource).AssemblyQualifiedName} to {typeof(TDestination).AssemblyQualifiedName}.");
}
}
}

@ -9,8 +9,9 @@
/// Converts an object to another. Creates a new object of <see cref="TDestination"/>.
/// </summary>
/// <typeparam name="TDestination">Type of the destination object</typeparam>
/// <typeparam name="TSource">Type of the source object</typeparam>
/// <param name="source">Source object</param>
TDestination Map<TDestination>(object source);
TDestination Map<TSource, TDestination>(TSource source);
/// <summary>
/// Execute a mapping from the source object to the existing destination object
@ -22,4 +23,11 @@
/// <returns>Returns the same <see cref="destination"/> object after mapping operation</returns>
TDestination Map<TSource, TDestination>(TSource source, TDestination destination);
}
public interface IObjectMapper<in TSource, TDestination>
{
TDestination Map(TSource source);
TDestination Map(TSource source, TDestination destination);
}
}

@ -1,23 +0,0 @@
using System;
using Volo.DependencyInjection;
namespace Volo.Abp.ObjectMapping
{
public sealed class NotImplementedObjectMapper : IObjectMapper, ISingletonDependency
{
/// <summary>
/// Singleton instance.
/// </summary>
public static NotImplementedObjectMapper Instance { get; } = new NotImplementedObjectMapper();
public TDestination Map<TDestination>(object source)
{
throw new NotImplementedException("Abp.ObjectMapping.IObjectMapper should be implemented in order to map objects.");
}
public TDestination Map<TSource, TDestination>(TSource source, TDestination destination)
{
throw new NotImplementedException("Abp.ObjectMapping.IObjectMapper should be implemented in order to map objects.");
}
}
}

@ -10,30 +10,32 @@ namespace Volo.Abp.AutoMapper
{
public class AbpAutoMapperModule_Basic_Tests : AbpIntegratedTest<AutoMapperTestModule>
{
private readonly IObjectMapper _objectMapper;
public AbpAutoMapperModule_Basic_Tests()
{
_objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
}
[Fact]
public void Should_Replace_ObjectMapper()
{
var objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
Assert.True(objectMapper is AutoMapperObjectMapper);
Assert.True(_objectMapper is AutoMapperObjectMapper);
}
[Fact]
public void Should_Map_Objects_With_AutoMap_Attributes()
{
var objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
var dto = objectMapper.Map<MyEntityDto>(new MyEntity {Number = 42});
var dto = _objectMapper.Map<MyEntity, MyEntityDto>(new MyEntity {Number = 42});
dto.Number.ShouldBe(42);
}
[Fact]
public void Should_Not_Map_Objects_With_AutoMap_Attributes()
{
var objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
Assert.ThrowsAny<Exception>(() =>
{
objectMapper.Map<MyNotMappedDto>(new MyEntity {Number = 42});
_objectMapper.Map<MyEntity, MyNotMappedDto>(new MyEntity {Number = 42});
});
}
}

@ -0,0 +1,26 @@
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.AutoMapper.SampleClasses;
using Volo.Abp.ObjectMapping;
using Volo.Abp.TestBase;
using Xunit;
namespace Volo.Abp.AutoMapper
{
public class AbpAutoMapperModule_Specific_ObjectMapper_Tests : AbpIntegratedTest<AutoMapperTestModule>
{
private readonly IObjectMapper _objectMapper;
public AbpAutoMapperModule_Specific_ObjectMapper_Tests()
{
_objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
}
[Fact]
public void Should_Use_Specific_Object_Mapper_If_Registered()
{
var dto = _objectMapper.Map<MyEntity, MyEntityDto2>(new MyEntity { Number = 42 });
dto.Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
}
}
}

@ -8,7 +8,7 @@ namespace Volo.Abp.AutoMapper
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAssemblyOf<AbpAutoMapperModule>();
services.AddAssemblyOf<AutoMapperTestModule>();
}
}
}

@ -0,0 +1,9 @@
using Volo.Abp.Application.Services.Dtos;
namespace Volo.Abp.AutoMapper.SampleClasses
{
public class MyEntityDto2 : EntityDto
{
public int Number { get; set; }
}
}

@ -0,0 +1,25 @@
using Volo.Abp.ObjectMapping;
using Volo.DependencyInjection;
namespace Volo.Abp.AutoMapper.SampleClasses
{
[ExposeServices(typeof(IObjectMapper<MyEntity, MyEntityDto2>))]
public class MyEntityToMyEntityDto2Mapper : IObjectMapper<MyEntity, MyEntityDto2>, ITransientDependency
{
public MyEntityDto2 Map(MyEntity source)
{
return new MyEntityDto2
{
Id = source.Id,
Number = source.Number + 1
};
}
public MyEntityDto2 Map(MyEntity source, MyEntityDto2 destination)
{
destination.Id = source.Id;
destination.Number = source.Number + 1;
return destination;
}
}
}
Loading…
Cancel
Save