When registering profiles resolvers are ignored, and so mapping fails. When regestering Assemblies it's fine, also when using the AddProfile<>() in standard instantiation it's also fine.
Based on the documentation and the shape of the .AddAutoMapper() -method, this is a bug in the behaviour. I want to avoid adding entire Assemblies as I will get duplicate mappings so I want to add individual profiles. This however isn't possible if one uses resolvers. The profiles work as expected, but the resolver is nowhere to be found in the ServiceCollection/ServiceProvider.
Is there a way I can workaround this?
Test that passes using .AddProfile in traditional instantiation
[Theory]
[InlineData("Frank", "Sinatra", "Frank Sinatra")]
public void AutoMapperIsManuallyInstanciatedSucceedingExample(string firstName, string lastName, string expected)
{
var source = new Source { FirstName = firstName, LastName = lastName };
var sut = new Mapper(new MapperConfiguration(x => x.AddProfile<TestProfile>()));
var result = sut.Map<Source, Destination>(source);
result.Should().NotBeNull();
result.FullName.Should().Be(expected);
}
Test that fails using .AddProfile in DI
[Theory]
[InlineData("Frank", "Sinatra", "Frank Sinatra")]
public void AutoMapperIsCorrectlyAddedFailingExample(string firstName, string lastName, string expected)
{
var source = new Source { FirstName = firstName, LastName = lastName };
var serviceCollection = new ServiceCollection();
serviceCollection
.AddSingleton<IOtherServiceClient, OtherServiceClient>()
.AddSingleton<SomeServiceWithMapping>()
.AddAutoMapper(x => x.AddProfile<TestProfile>());
var serviceProvider = serviceCollection.BuildServiceProvider();
var sut = serviceProvider.GetService<SomeServiceWithMapping>();
var result = sut.Map<Source, Destination>(source);
Logger.LogInformation(serviceCollection.GetServiceDescriptorsAsConsoleTable());
result.Should().NotBeNull();
result.FullName.Should().Be(expected);
}
Test that Passes using Assemblies in DI
[Theory]
[InlineData("Frank", "Sinatra", "Frank Sinatra")]
public void AutoMapperIsCorrectlyAddedSucceedingExample(string firstName, string lastName, string expected)
{
var source = new Source { FirstName = firstName, LastName = lastName };
var serviceCollection = new ServiceCollection();
serviceCollection
.AddSingleton<IOtherServiceClient, OtherServiceClient>()
.AddSingleton<SomeServiceWithMapping>()
.AddAutoMapper(GetType().Assembly);
var serviceProvider = serviceCollection.BuildServiceProvider();
var sut = serviceProvider.GetService<SomeServiceWithMapping>();
var result = sut.Map<Source, Destination>(source);
Logger.LogInformation(serviceCollection.GetServiceDescriptorsAsConsoleTable());
result.Should().NotBeNull();
result.FullName.Should().Be(expected);
}
Classes and Interfaces
public class OtherServiceClient : IOtherServiceClient
{
public void Send(int num) { }
}
public interface IOtherServiceClient
{
public void Send(int num);
}
public class SomeServiceWithMapping
{
private readonly IOtherServiceClient _otherServiceClient;
private readonly IMapper _mapper;
public SomeServiceWithMapping(IOtherServiceClient otherServiceClient, IMapper mapper)
{
_otherServiceClient = otherServiceClient;
_mapper = mapper;
}
public bool HasServiceClient() => _otherServiceClient is not null;
public void SendNum(int num) => _otherServiceClient.Send(num);
public TDestination Map<TSource, TDestination>(TSource source) => _mapper.Map<TSource, TDestination>(source);
}
public class TestProfile : Profile
{
public TestProfile()
{
CreateMap<Source, Destination>()
.ForMember(x => x.FullName, opt => opt.MapFrom<FullNameResolver>()) // Fails
//.ForMember(x => x.FullName, opt => opt.MapFrom(y => $"{y.FirstName} {y.LastName}")) // Passes
;
}
}
public class FullNameResolver : IValueResolver<Source, Destination, string>
{
public string Resolve(Source source, Destination destination, string destMember, ResolutionContext context)
{
return $"{source.FirstName} {source.LastName}";
}
}
public class Source
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Destination
{
public string FullName { get; set; }
}
When registering profiles resolvers are ignored, and so mapping fails. When regestering Assemblies it's fine, also when using the AddProfile<>() in standard instantiation it's also fine.
Based on the documentation and the shape of the .AddAutoMapper() -method, this is a bug in the behaviour. I want to avoid adding entire Assemblies as I will get duplicate mappings so I want to add individual profiles. This however isn't possible if one uses resolvers. The profiles work as expected, but the resolver is nowhere to be found in the ServiceCollection/ServiceProvider.
Is there a way I can workaround this?
Test that passes using .AddProfile in traditional instantiation
Test that fails using .AddProfile in DI
Test that Passes using Assemblies in DI
Classes and Interfaces