Reputation: 1061
I'm having issues getting aufotac to inject into my autopmapper typeconverters. I've tried some different ways but I'm currently stuck using the code below. The closest I've come to finding a solution is the code below (borrowed small bits from http://thoai-nguyen.blogspot.se/2011/10/autofac-automapper-custom-converter-di.html). His sample seems to work 1:1 but haven't been able to locate what I'm missing. As usual extracted the relevant bits, let me know if it's insufficient.
My autofac bootstrapper:
public class AutoFacInitializer
{
public static void Initialize()
{
//Mvc
var MvcContainer = BuildMvcContainer();
DependencyResolver.SetResolver(new AutofacDependencyResolver(MvcContainer));
//Web API
var ApiContainer = BuildApiContainer();
var ApiResolver = new AutofacWebApiDependencyResolver(ApiContainer);
GlobalConfiguration.Configuration.DependencyResolver = ApiResolver;
}
private static IContainer BuildApiContainer()
{
var builder = new ContainerBuilder();
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterApiControllers(assembly);
return BuildSharedDependencies(builder, assembly);
}
private static IContainer BuildMvcContainer()
{
var builder = new ContainerBuilder();
var assembly = typeof (MvcApplication).Assembly;
builder.RegisterControllers(assembly);
builder.RegisterFilterProvider();
return BuildSharedDependencies(builder, assembly);
}
private static IContainer BuildSharedDependencies(ContainerBuilder builder, Assembly assembly)
{
//----Build and return container----
IContainer container = null;
//Automapper
builder.RegisterAssemblyTypes(assembly).AsClosedTypesOf(typeof(ITypeConverter<,>)).AsSelf();
AutoMapperInitializer.Initialize(container);
builder.RegisterAssemblyTypes(assembly).Where(t => typeof(IStartable).IsAssignableFrom(t)).As<IStartable>().SingleInstance();
//Modules
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterModule(new NLogLoggerAutofacModule());
//Automapper dependencies
builder.Register(x => Mapper.Engine).As<IMappingEngine>().SingleInstance();
//Services, repos etc
builder.RegisterGeneric(typeof(SqlRepository<>)).As(typeof(IRepository<>)).InstancePerDependency();
container = builder.Build();
return container;
}
}
My Automap bootstrapper / initializer:
namespace Supportweb.Web.App_Start
{
public class AutoMapperInitializer
{
public static void Initialize(IContainer container)
{
Mapper.Initialize(map =>
{
map.CreateMap<long?, EntityToConvertTo>().ConvertUsing<LongToEntity<NavigationFolder>>();
map.ConstructServicesUsing(t => container.Resolve(t));
});
Mapper.AssertConfigurationIsValid();
}
}
}
The typeconverter that im trying to get working:
public class LongToEntity<T> : ITypeConverter<long?, T>
{
private readonly IRepository<T> _repo;
public LongToEntity(IRepository<T> repo)
{
_repo = repo;
}
public T Convert(ResolutionContext context)
{
long id = 0;
if (context.SourceValue != null)
id = (long)context.SourceValue;
return _repo.Get(id);
}
}
Except for the converter all mappings works fine. The error seems to indicate that I'm lacking an ioc reference but I've tried but the mentioned ITypeConverter<,> and LongToEntity<> and variations which doesn't seem to help.
Upvotes: 4
Views: 3396
Reputation: 139758
You have three problems with your current code:
You need to call ConstructServicesUsing
before registering any mapping as described in the linked article:
The tricky thing is we need to call that method before we register mapper classes.
So the correct Mapper.Initialize
is the follwing:
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(t => container.Resolve(t));
map.CreateMap<long?, EntityToConvertTo>()
.ConvertUsing<LongToEntity<NavigationFolder>>();
});
Because your LongToEntity<T>
is an open generic you cannot use AsClosedTypesOf
but you need to use here also the RegisterGeneric
for the registration:
So change your ITypeConverter<,>
registration from:
builder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(ITypeConverter<,>)).AsSelf();
To use the RegisterGeneric
method:
builder.RegisterGeneric(typeof(LongToEntity<>)).AsSelf();
Because you have moved the Automapper initialization into a separate method AutoMapperInitializer.Initialize
you cannot use the clojure trick from the article, so you need to call it after you have created the container:
container = builder.Build();
AutoMapperInitializer.Initialize(container);
return container;
Upvotes: 8