I've been using Automapper and Autofac in a .Net app for some time. I configured them this way:
builder.RegisterAssemblyTypes(typeof (OneOfMyMappingProfiles).Assembly)
.Where(t => t.IsSubclassOf(typeof (Profile)))
.As<Profile>();
builder.Register(ctx => new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers))
.AsImplementedInterfaces()
.SingleInstance()
.OnActivating(x =>
{
foreach (var profile in x.Context.Resolve<IEnumerable<Profile>>())
{
x.Instance.AddProfile(profile);
}
});
builder.RegisterType<MappingEngine>()
.As<IMappingEngine>().SingleInstance();
With the latest build of Automapper (4.2) the API has changed and I am having trouble translating to the new API. ConfigurationStore no longer seems to exist. According to the docs, the way to register with an IOC is now like this:
var profiles =
from t in typeof (AutoMapperRegistry).Assembly.GetTypes()
where typeof (Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
For<MapperConfiguration>().Use(config);
For<IMapper>().Use(ctx => ctx.GetInstance<MapperConfiguration>().CreateMapper(ctx.GetInstance));
BUT that is using StructureMap. The first half of this is no problem, but I am not sure how to translate the "For<>.Use()" portion. How do I do that in Autofac?
OK. Worked it out. Here is the replacement:
var profiles =
from t in typeof(LocationMappingProfile).Assembly.GetTypes()
where typeof(Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
builder.Register(ctx => new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
}));
builder.Register(ctx => ctx.Resolve<MapperConfiguration>().CreateMapper()).As<IMapper>();
UPDATE
Here is an example of a profile. Super simple. In this case I only have one mapping. But I could add others. I try to keep them logically together by Entity. So in this case, any future mapping from or to ProviderDetail would be in this file. Mappings to a different entity would be in a separate mappingprofile class. Nothing injected in the profile class:
public class ProviderMappingProfile : Profile
{
protected override void Configure()
{
CreateMap<ProviderDetail, ProviderListItem>();
}
}
UPDATE2
Here is an example of a test that proves the mapping is correct:
public class ProviderMappingProfileTests
{
[Fact]
public void CreateMap_ProviderDetailToProviderQueryResult_IsValid()
{
var config = new MapperConfiguration(cfg =>
cfg.CreateMap<ProviderDetail, ProviderListItem>()
);
config.AssertConfigurationIsValid();
}
}
Another interesting method of registering Automapper through Autofac, with a dynamic registration of all custom profiles in your assemblies.
Here you register profiles for all assemblies you need.
builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Program)))
.Where(t => t.BaseType == typeof(Profile)
&& !t.IsAbstract && t.IsPublic)
.As<Profile>();
And here you resolve those:
builder.Register(ctx => new MapperConfiguration(cfg =>
{
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
cfg.AddProfile(profile);
}));
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper())
.As<IMapper>()
.SingleInstance();
Also, can use
.CreateMapper(ctx.Resolve)
instead of
.CreateMapper()
to resolve internal dependencies in profiles. But it will require removing
.SingleInstance()
from registration.
And here is a usage BTW:
public SomeAutowiredClass
{
public IMapper Mapper { get; set; }
public void SomeMethod(SomeModel model){
Mapper.Map<AnotherModel>(model)
}
}
I agreed above solution. Instead of using reflection can't we do like below?.
public static IMapper RegisterAutoMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ApiMappingProfile1>();
cfg.AddProfile<ApiMappingProfile2>();
// Add all your profiles
});
var mapper = config.CreateMapper();
return mapper;
}
In Autofac registration
builder.Register(c => AutoMapperConfig.RegisterAutoMapper()).As<IMapper>()
.InstancePerLifetimeScope().PropertiesAutowired().PreserveExistingDefaults();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With