How do I use AutoMapper with Ninject.Web.Mvc?
Setup
I have an AutoMapperConfiguration
static class that sets up the AutoMapper mappings:
static class AutoMapperConfiguration()
{
internal static void SetupMappings()
{
Mapper.CreateMap<long, Category>.ConvertUsing<IdToEntityConverter<Category>>();
}
}
where IdToEntityConverter<T>
is a custom ITypeConverter
that looks like this:
class IdToEntityConverter<T> : ITypeConverter<long, T> where T : Entity
{
private readonly IRepository _repo;
public IdToEntityConverter(IRepository repo)
{
_repo = repo;
}
public T Convert(ResolutionContext context)
{
return _repo.GetSingle<T>(context.SourceValue);
}
}
IdToEntityConverter
takes an IRepository
in its constructor in order to convert an ID back to the actual entity by hitting up the database. Notice how it doesn't have a default constructor.
In my ASP.NET's Global.asax
, this is what I have for OnApplicationStarted()
and CreateKernel()
:
protected override void OnApplicationStarted()
{
// stuff that's required by MVC
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
// our setup stuff
AutoMapperConfiguration.SetupMappings();
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<NHibRepository>();
return kernel;
}
So OnApplicationCreated()
will call AutoMapperConfiguration.SetupMappings()
to set up the mappings and CreateKernel()
will bind an instance of NHibRepository
to the IRepository
interface.
Problem
Whenever I run this code and try to get AutoMapper to convert a category ID back to a category entity, I get an AutoMapperMappingException
that says no default constructor exists on IdToEntityConverter
.
Attempts
Added a default constructor to IdToEntityConverter
. Now I get a NullReferenceException
, which indicates to me that the injection isn't working.
Made the private _repo
field into a public property and added the [Inject]
attribute. Still getting NullReferenceException
.
Added the [Inject]
attribute on the constructor that takes an IRepository
. Still getting NullReferenceException
.
Thinking that perhaps Ninject can't intercept the AutoMapperConfiguration.SetupMappings()
call in OnApplicationStarted()
, I moved it to something that I know is injecting correctly, one of my controllers, like so:
public class RepositoryController : Controller
{
static RepositoryController()
{
AutoMapperConfiguration.SetupMappings();
}
}
Still getting NullReferenceException
.
Question
My question is, how do I get Ninject to inject an IRepository
into IdToEntityConverter
?
You have to give AutoMapper access to the DI container. We use StructureMap, but I guess the below should work with any DI.
We use this (in one of our Bootstrapper tasks)...
private IContainer _container; //Structuremap container
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(_container.GetInstance);
map.AddProfile<MyMapperProfile>();
}
@ozczecho's answer is spot-on, but I'm posting the Ninject version of the code because it has one little caveat that caught us for a while:
IKernel kernel = null; // Make sure your kernel is initialized here
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(t => kernel.Get(t));
});
You can't just pass in kernel.Get
to map.ConstructServicesUsing
because that method has a params
parameter in addition to the Type. But since params are optional, you can just create the lambda expression to generate an anonymous function to get you what you need.