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.
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;
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