Could anyone help make the following example work with Autofac?
public class AutoMapperRegistry : Registry
{
public AutoMapperRegistry()
{
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));
}
}
No idea, I've never used AutoFac.
@TDK1964: You'll need something along the lines of the following.
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes().AssignableTo(typeof (Profile));
//register your configuration as a single instance
builder.Register(c => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in c.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope();
mpetito,
Thanks for the info but I'm still having problems. This is how I've configured by may mappings so far.
public class DomainToViewModelMappingProfile : Profile
{
public override string ProfileName
{
get { return "DomainToViewModelMappings"; }
}
protected override void Configure()
{
CreateMap<Training,TrainingViewModel>();
CreateMap<Course, CourseViewModel>();
}
}
public class ViewModelToDomainMappingProfile : Profile
{
public override string ProfileName
{
get { return "ViewModelToDomainMappings"; }
}
protected override void Configure()
{
CreateMap<TrainingViewModel, Training>();
CreateMap<CourseViewModel, Course>();
}
}
public static class Bootstrapper
{
public static void Run()
{
SetAutofacContainer();
AutoMapperConfiguration.Configure();
}
private static void SetAutofacContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
builder.RegisterType<DbFactory>().As<IDbFactory>().InstancePerRequest();
// Repositories
builder.RegisterAssemblyTypes(typeof(TrainingRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerRequest();
// Services
builder.RegisterAssemblyTypes(typeof(CourseService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces().InstancePerRequest();
// TODO AutoMapper registrations...
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
@TDK1964 Where you have your TODO, you should be able to use my code example nearly verbatim.
The general steps are:
Profile classes with the container so you can resolve them in the next step. This could be done using assembly scanning, in very much the same way as the repositories and services in your code.MapperConfiguration as a singleton, and use a custom delegate to add the profiles to the configuration when it is constructed.IMapper, again using a custom delegate to acquire an instance from your singleton MapperConfiguration.MapperConfiguration on application start and assert its validity.This is what I've done so far, but it's not working but I'm getting this error
Missing type map configuration or unsupported mapping.
Mapping types:
TrainingViewModel -> Training
TrainingViewModel -> Training
Destination path:
Training
Source value:
TrainingViewModel
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes().AssignableTo(typeof(DomainToViewModelMappingProfile));
builder.RegisterAssemblyTypes().AssignableTo(typeof(ViewModelToDomainMappingProfile));
//register your configuration as a single instance
builder.Register(c => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in c.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope();
@mpetito, you code doesn't work. The only way I got the injection to work was doing this..
builder.Register(c => new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AppProfile());
})).AsSelf().SingleInstance();
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope();
public class AppProfile : Profile
{
protected override void Configure()
{
CreateMap<Training, TrainingViewModel>().ReverseMap();
CreateMap<Course, CourseViewModel>().ReverseMap();
}
}
@TDK1964 The first step outlined above was:
Register your Profile classes with the container so you can resolve them in the next step. This could be done using assembly scanning, in very much the same way as the repositories and services in your code.
You've explicitly added your profile in the MapperConfiguration which may be fine. However, if you have many profiles, you may want to use assembly scanning. This way your configuration looks like the following:
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes().AssignableTo(typeof (Profile)).As<Profile>();
Sorry, I originally missed the As<Profile>() call. Note you may also need to specify which assembly (or assemblies) to scan for profiles.
Once your profiles are registered with the container, you should be able resolve all of your profiles in your configuration callback:
//add your profiles from the container, instead of cfg.AddProfile(new AppProfile());
foreach (var profile in c.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
@mpetito unfortunately is still doesn't work!
@TDK1964 did you get this to work? Maybe my issue is different but I'm also trying to get 4.2 working with autofac.
My error is Cannot resolve parameter 'AutoMapper.IMapper mapper'
builder.Register(c => new MapperConfiguration(cfg =>
{
cfg.CreateMap<IdentityUser, AspNetUser>().ReverseMap();
})).AsSelf().SingleInstance();
builder.Register(ctx => ctx.Resolve<MapperConfiguration>().CreateMapper()).As<IMapper>();
//or
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope();
@Eonasdan the only way I got it to work was using the manual way (see earlier posts). Using the foreach way did not work at all.
I must say I find asking for any kind help with AF has been extremely frustrating, Especially when the first response for help was met with "No idea, I've never used AutoFac"
@TDK1964 I understand, but autofac does at least register that way for you? Are you using IMapper int the ctro of your class then?
@TDK1964 strange. I just tried this:
builder.RegisterAssemblyTypes().AssignableTo(typeof(Profile)).As<Profile>();
builder.Register(c => new MapperConfiguration(cfg =>
{
foreach (var profile in c.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope();
and it worked!
Edit: scratch that. I forgot I had commented out the use of IMapper so I could work on something else. The above code didn't cause an error for me however
@TDK1964 I got my code working (insert Picard facepalm). I'm happy to talk to you if you want some help solving your issue.
@Eonasdan when I try the foreach way I just get "Missing type map configuration or unsupported mapping"
How are you defining your profiles?
did you put builder.RegisterAssemblyTypes().AssignableTo(typeof (Profile)).As<Profile>(); first?
At the moment I have one profile:
public class IdentityUserAspNetUserMapProfile : Profile
{
protected override void Configure()
{
CreateMap<IdentityUser, AspNetUser>().ReverseMap();
CreateMap<AspNetUser, IdentityUser>().ReverseMap();
}
}
Maybe you've got a bad profile somewhere? Have you tried systematically trying them off and back on one at a time?
@TDK1964 What version are you using? It appears the version 5 (the github version) is different from 4.2 (latest github) and I too get "Missing type map configuration or unsupported mapping" with v5.
@jbogard what's changed with the Profile class between 4.2 and 5?
This is my config. I don't think the profiles are working because cfg.AddProfile(profile); is never hit.
public static class Bootstrapper
{
public static void Run()
{
SetAutofacContainer();
AutoMapperConfiguration.Configure();
}
private static void SetAutofacContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
builder.RegisterType<DbFactory>().As<IDbFactory>().InstancePerRequest();
// Repositories
builder.RegisterAssemblyTypes(typeof(TrainingRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerRequest();
// Services
builder.RegisterAssemblyTypes(typeof(CourseService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces().InstancePerRequest();
// AutoMapper
// Register all the profiles
builder.RegisterAssemblyTypes().AssignableTo(typeof(Profile)).As<Profile>();
builder.Register(c => new MapperConfiguration(cfg =>
{
//cfg.AddProfile(new AppProfile());
foreach (var profile in c.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
builder.Register(c => c.Resolve<MapperConfiguration>()
.CreateMapper(c.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
public class AutoMapperConfiguration
{
public static void Configure()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AppProfile());
});
}
}
public class AppProfile : Profile
{
protected override void Configure()
{
CreateMap<Training, TrainingViewModel>().ReverseMap();
}
}
I was able to take the code from @mpetito and get it to work in my project. Here is my code:
public class AutoMapperModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DomainToViewModelMappingProfile>().As<Profile>();
builder.RegisterType<ViewModelToDomainMappingProfile>().As<Profile>();
builder.Register(context => new MapperConfiguration(configuration =>
{
foreach (var profile in context.Resolve<IEnumerable<Profile>>())
{
configuration.AddProfile(profile);
}
}))
.AsSelf()
.SingleInstance();
builder.Register(context => context.Resolve<MapperConfiguration>()
.CreateMapper(context.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
}
I am using AutoMapper v4.2.1, AutoMapper.EF6 v0.3.0, Autofac v3.5.2, and Autofac.Mvc5 v3.3.4 from NuGet.
@kibner but there's no point in registering every profile in autofac, you might as well just add each one to the MapperConfiguration part
@Eonasdan Then don't use the foreach loop and just add the ones you need inside the MapperConfiguration.
I think the issue @TDK1964 is experiencing may be because the wrong 'Register' method is being called. I took the code I posted earlier and replaced the lines:
builder.RegisterType<DomainToViewModelMappingProfile>().As<Profile>();
builder.RegisterType<ViewModelToDomainMappingProfile>().As<Profile>();
with this:
builder.RegisterAssemblyTypes().AssignableTo(typeof(DomainToViewModelMappingProfile));
builder.RegisterAssemblyTypes().AssignableTo(typeof(ViewModelToDomainMappingProfile));
Doing that gave me a "Missing type map configuration or unsupported mapping." error like @TDK1964 was experiencing. I believe the problem lies with using RegisterAssemblyTypes() without loading from an assembly. When I have used that method elsewhere, it usually looked like builder.RegisterAssemblyTypes(Assembly.Load("<assembly name goes here>")).
I am not intimately familiar with AutoFac so my reasoning could very well be wrong, but I'm pretty sure my suggested fix should work.
This worked for me
``` C#
public class AutoMapperModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//register all profile classes in the calling assembly
builder.RegisterAssemblyTypes(typeof(AutoMapperModule).Assembly).As
builder.Register(context => new MapperConfiguration(cfg =>
{
foreach (var profile in context.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
// ~/App_Start/AutofacConfig.cs
public class AutofacConfig
{
public static void Register()
{
var builder = new ContainerBuilder();
// .....
builder.RegisterModule(new AutoMapperModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
// Global.asax
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// ......
AutofacConfig.Register();
}
}
//In my controller
public class ProductLicensesController : Controller
{
private readonly IMapper mapper;
public ProductLicensesController( IMapper mapper)
{
//. . .
this.mapper = mapper;
}
// then in some action method
var productLicense = mapper.Map
```
@Eonasdan The code works great, can anyone explain
this line of code:
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve))
@badian96 the c is a lambda expression for the AutoFace context. So the code is supposed to go find all of the Profiles in the assembly and Resolve it into a Profile type. Is that what you're asking?
Also, if you got the foreach loop to work, it stopped working for me again.
CreateMapper(c.Resolve)
I don't understand what is the c.Resolve here.
And the profiles are working just fine for me as you posted.
c.Resolve is a method group for the Resolve method of the Autofac context.
You'll notice that the CreateMapper method accepts a parameter of type Func<Type, object>, a factory for dependencies by type. An overload of the Resolve method matches this signature (there is an overload which accepts a single Type argument and returns an object of that Type). This allows Autofac / mapping dependencies to be resolved from your container (following IoC principles).
To answer a couple of questions regarding the foreach:
foreach and you'll get the missing mapping error.MapperConfiguration explicitly instead of using a foreach loop.I have a problem, when inside of my profiles i use a nested mapping - meaning I use the static
Mapper.Map<> inside my profile configuration. AssertIsConfigurationValid() works fine in the unit tests but inside my application I get "Automapper missing type map configuration or unsupported mapping". I guess it's something to do with Autofac registration, did anyone experience this?
In unit tests the mapping works perfectly, I guess it's something with Autofac, anyone knows?
Apologies as I know this is an old issue. However the following worked for me when trying to perform assembly scanning for all Mapping Profiles:
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AssignableTo(typeof(Profile)).As<Profile>();
builder.Register(c => new MapperConfiguration(cfg =>
{
foreach (var profile in c.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
builder.Register(ctx => ctx.Resolve<MapperConfiguration>().CreateMapper()).As<IMapper>();
}
builder.Register(c => new MapperConfiguration(cfg =>
{
cfg.AddProfile(typeof(AutoMapperProfile));
})).AsSelf().SingleInstance();
builder.Register(ctx => ctx.Resolve<MapperConfiguration>().CreateMapper()).As<AutoMapper.IMapper>();
public class AutoMapperProfile : Profile
{
protected override void Configure()
{
CreateMap<SubscribersListModel, SubscribersListDto>().ReverseMap();
CreateMap<SubscribersListDto, SubscribersListModel>().ReverseMap();
}
}
Work fine for me 5.2.0 Mapper
Anyone experienced problems with ValueResolvers? I am getting the message
ObjectDisposedException: This resolve operation has already ended. When registering components using lambdas, the IComponentContext 'c' parameter to the lambda cannot be stored. Instead, either resolve IComponentContext again from 'c', or resolve a Func<> based factory to create subsequent components from.
Any ideas?
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve<IComponentContext>().Resolve)).As<IMapper>().InstancePerLifetimeScope(); @SamiAl90
Any reason why in this code the Mapper is created InstancePerLifeTimeScope:
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
This could also be SingleInstance like for the MappingConfiguration?
You want the IMapper to be scoped to whatever your per-request container
is scoped as. If you're using a nested/child container per request, then
the above is what you want.
I'm super careful about static/singletons, really only configuration should
be singleton.
On Tue, Mar 6, 2018 at 8:34 AM, Mike notifications@github.com wrote:
Any reason why in this code the Mapper is created InstancePerLifeTimeScope:
builder.Register(c => c.Resolve
().CreateMapper(c.Resolve))
.As()
.InstancePerLifetimeScope();This could also be SingleInstance like for the MappingConfiguration?
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1109#issuecomment-370800208,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGYMpG-XEJ48uRDxBSYc9TODQHzlrhHks5tbp5ZgaJpZM4HZ5Ph
.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
This worked for me
``` C#();
public class AutoMapperModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//register all profile classes in the calling assembly
builder.RegisterAssemblyTypes(typeof(AutoMapperModule).Assembly).As
// ~/App_Start/AutofacConfig.cs
public class AutofacConfig
{
public static void Register()
{
var builder = new ContainerBuilder();
// Global.asax
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// ......
AutofacConfig.Register();
}
}
//In my controller
public class ProductLicensesController : Controller
{
// then in some action method
var productLicense = mapper.Map(viewModel);
```