如何在Ninject.Web.Mvc中使用AutoMapper?
建立
我有一个设置AutoMapper映射的AutoMapperConfiguration
静态类:
static class AutoMapperConfiguration()
{
internal static void SetupMappings()
{
Mapper.CreateMap<long, Category>.ConvertUsing<IdToEntityConverter<Category>>();
}
}
IdToEntityConverter<T>
是一个定制的ITypeConverter
,它看起来像这样:
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
在其构造函数中接受一个IRepository
,以通过点击数据库将ID转换回实际的实体。 注意它没有默认的构造函数。
在我的ASP.NET的Global.asax
,这是我对OnApplicationStarted()
和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;
}
所以OnApplicationCreated()
会调用AutoMapperConfiguration.SetupMappings()
来设置映射,而CreateKernel()
会将NHibRepository
一个实例绑定到IRepository
接口。
问题
每当我运行此代码并尝试让AutoMapper将类别标识转换回类别实体时,我会得到一个AutoMapperMappingException
,它表示IdToEntityConverter
上不存在默认构造IdToEntityConverter
。
尝试
为IdToEntityConverter
添加了一个默认构造IdToEntityConverter
。 现在我得到一个NullReferenceException
,它向我表明注入不起作用。
将私人_repo
字段设置为公共属性并添加[Inject]
属性。 仍然得到NullReferenceException
。
在采用IRepository
的构造函数中添加了[Inject]
属性。 仍然得到NullReferenceException
。
考虑到Ninject可能无法拦截OnApplicationStarted()
的AutoMapperConfiguration.SetupMappings()
调用,我将它移动到我知道正在注入的东西,我的控制器之一,如下所示:
public class RepositoryController : Controller
{
static RepositoryController()
{
AutoMapperConfiguration.SetupMappings();
}
}
仍然得到NullReferenceException
。
题
我的问题是,我如何让Ninject将IRepository
注入到IdToEntityConverter
?
你必须让AutoMapper访问DI容器。 我们使用StructureMap,但我想下面应该适用于任何DI。
我们使用这个(在我们的一个Bootstrapper任务中)...
private IContainer _container; //Structuremap container
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(_container.GetInstance);
map.AddProfile<MyMapperProfile>();
}
@ ozczecho的答案是现货,但我发布了Ninject版本的代码,因为它有一点让我们想起了一段时间:
IKernel kernel = null; // Make sure your kernel is initialized here
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(t => kernel.Get(t));
});
你不能只传入kernel.Get
map.ConstructServicesUsing
因为除了Type之外,该方法还有一个params
参数。 但是因为params是可选的,所以你可以创建lambda表达式来生成一个匿名函数来得到你所需要的。